How to convert bytes to half-floats in Swift?

拟墨画扇 提交于 2019-12-02 05:27:45
Martin R

There is no 16-bit floating point type in Swift, but you can convert the results to 32-bit floating point numbers (Float). This thread

contains a lot of information about the Half-precision floating-point format, and various conversion methods. The crucial hint however is in Ian Ollman's answer:

On OS X / iOS, you can use vImageConvert_PlanarFtoPlanar16F and vImageConvert_Planar16FtoPlanarF. See Accelerate.framework.

Ian did provide no code however, so here is a possible implementation in Swift:

func areaHistogram(image : UIImage) {

    let inputImage = CIImage(image: image)

    let totalBytes : Int = bpp * BINS //8 * 64 for example
    let bitmap = calloc(1, totalBytes)

    let filter = CIFilter(name: "CIAreaHistogram")!
    filter.setValue(inputImage, forKey: kCIInputImageKey)
    filter.setValue(CIVector(x: 0, y: 0, z: image.size.width, w: image.size.height), forKey: kCIInputExtentKey)
    filter.setValue(BINS, forKey: "inputCount") 
    filter.setValue(1, forKey: "inputScale")

    let myEAGLContext = EAGLContext(API: .OpenGLES2)
    let options = [kCIContextWorkingColorSpace : kCFNull]
    let context : CIContext = CIContext(EAGLContext: myEAGLContext, options: options)
    context.render(filter.outputImage!, toBitmap: bitmap, rowBytes: totalBytes, bounds: filter.outputImage!.extent, format: kCIFormatRGBAh, colorSpace: CGColorSpaceCreateDeviceRGB())

    // *** CONVERSION FROM 16-bit TO 32-bit FLOAT ARRAY STARTS HERE ***

    let comps = 4 // Number of components (RGBA)

    // Array for the RGBA values of the histogram: 
    var rgbaFloat = [Float](count: comps * BINS, repeatedValue: 0)

    // Source and image buffer structure for vImage conversion function:
    var srcBuffer = vImage_Buffer(data: bitmap, height: 1, width: UInt(comps * BINS), rowBytes: bpp * BINS)
    var dstBuffer = vImage_Buffer(data: &rgbaFloat, height: 1, width: UInt(comps * BINS), rowBytes: comps * sizeof(Float) * BINS)

    // Half-precision float to Float conversion of entire buffer:
    if vImageConvert_Planar16FtoPlanarF(&srcBuffer, &dstBuffer, 0) == kvImageNoError {
        for bin in 0 ..< BINS {
            let R = rgbaFloat[comps * bin + 0]
            let G = rgbaFloat[comps * bin + 1]
            let B = rgbaFloat[comps * bin + 2]
            print("R/G/B = \(R) \(G) \(B)")
        }
    }

    free(bitmap)
}

Remarks:

  • You need to import Accelerate.
  • Note that your code allocates totalBytes * bpp bytes instead of the necessary totalBytes.
  • The kCIFormatRGBAh pixel format is not supported on the Simulator (as of Xcode 7), so you have to test the code on a real device.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!