Fast UInt to Float conversion in Swift

417 views Asked by At

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?

1

There are 1 answers

3
Martin R On BEST ANSWER

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);
}