如何将字节转换为Swift中的半浮点数?

如何在Swift中将两个字节(UInt8)转换为半精度(16位)Float,例如在读取具有kCIFormatRGBAh的CIAreaHistogram的输出时所需的字节,如下例所示:

func areaHistogram(image : UIImage) { let inputImage = CIImage(image: image) let totalBytes : Int = bpp * BINS //8 * 64 for example let bitmap : UnsafeMutablePointer<Void> = calloc(totalBytes, bpp) 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()) let bytes = UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(bitmap), count: bpp * BINS) //HOW TO CONVERT TWO CONSECUTIVE BYTES AS 16-BIT FLOATS? //THIS CODE DOES NOT WORK (I guess because Float in Swift is 32-bit): for var i=0; i < self.bpp * self.BINS; i+=self.bpp { let bitsR = UnsafePointer<Float._BitsType>(self.queryHist!)[i+0].bigEndian let R = Float( Float._fromBitPattern(bitsR) ) let bitsG = UnsafePointer<Float._BitsType>(self.queryHist!)[i+2].bigEndian let G = Float( Float._fromBitPattern(bitsG) ) let bitsB = UnsafePointer<Float._BitsType>(self.queryHist!)[i+4].bigEndian let B = Float( Float._fromBitPattern(bitsB) ) print("R/G/B = \(R) \(G) \(B)") } free(bitmap) } 

在Swift中没有16位浮点types,但可以结果转换为32位浮点数( Float )。 这个线程

  • 32位到16位浮点转换

包含大量有关半精度浮点格式的信息以及各种转换方法。 然而,至关重要的是Ian Ollman的回答 :

在OS X / iOS上,可以使用vImageConvert_PlanarFtoPlanar16FvImageConvert_Planar16FtoPlanarF 。 请参阅Accelerate.framework。

伊恩没有提供代码,所以这是一个可能的实现在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) } 

备注:

  • 您需要import Accelerate
  • 请注意,您的代码分配totalBytes * bpp字节,而不是必要的totalBytes
  • 模拟器不支持kCIFormatRGBAh像素格式(从Xcode 7开始),因此您必须在真实设备上testing代码。