I am doing some realtime image analysis on a live videostream. I am using vImage to calculate histograms and vDSP for some further processing. I have Objective-C code that has been working well over the years. I am now about to convert it to Swift. And while it works it is too slow. I have found that the main problem is converting the vImage histogram, which is UInt (vImagePixelCount), to Float that vDSP can handle. In Objective-C I am using vDSP to do the conversion:
err = vImageHistogramCalculation_Planar8(&vBuffY,histogramY, 0);
vDSP_vfltu32((const unsigned int*)histogramY,2,histFloatY,1,256);
However, the vImage histogram is UInt, not UInt32, so I can't use vDSP_vfltu32 in Swift. Instead I am using
let err = vImageHistogramCalculation_Planar8(&vBuffY, &histogramY, 0)
let histFloatY = histogramY.compactMap{ Float($0) }
The problem is that this code is more than 100 times slower than the objective-C version. Are there any alternatives that are faster?
vImageHistogramCalculation_Planar8()
writes the histogram into a buffer with 256 elements of type vImagePixelCount
which is a type alias for unsigned long
in C, and that is a 64-bit integer on 64-bit platforms.
Your Objective-C code “cheats” by casting the unsigned long pointer to an unsigned int pointer in the call to vDSP_vfltu32 ()
and setting the stride to 2
. So what happens here is that the lower 32-bit of each unsigned long
are converted to a float
. That works as long as the counts do not exceed the value 232-1.
You can do exactly the same in Swift, only that the type casting is here done by “rebinding” the memory:
let err = vImageHistogramCalculation_Planar8(&vBuffY, &histogramY, 0)
histogramY.withUnsafeBytes {
let uint32ptr = $0.bindMemory(to: UInt32.self)
vDSP_vfltu32(uint32ptr.baseAddress!, 2, &histFloatY, 1, 256);
}