2015-10-04 101 views
1

如何可以转换两个字节(UINT8)到半精度(16位)漂浮在夫特,如阅读CIAreaHistogram与kCIFormatRGBAh输出时,如在下面的例子中需要:如何将字节转换为Swift中的半浮点数?

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) 
} 
+0

首先,窄下来到你的问题的最简单可行的娱乐。第二个......你如何期望它能够正确地形成一个32位浮点数? – nhgrif

+0

首先,我认为这已经是我的问题的一个非常简单的娱乐了,因为据我所知,iOS不会处理16位浮点数(金属除外),但是对于CIAreaHistogram这种非常特殊的情况。其次,说实话,我不希望它能够工作,因为Swift中的Float是32位 - 当然需要4个字节 - 但我找不到除CGFloat之外的16位Float版本(但是,不与UnsafePointer结合使用_BitsType)。 – Klaus

回答

3

没有16位浮点型斯威夫特,但你可以转换 结果为32位浮点数(Float)。 这个线程

包含了很多关于 Half-precision floating-point format信息和各种转换方法。然而,关键的提示是在Ian Ollman's answer

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

伊恩但是没有提供任何代码,所以这里是一个可能的实现 斯威夫特:

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开始),因此您必须在真实设备上测试代码。
+1

你刚才发现了这一切吗?太棒了。 – matt

+0

非常感谢这个详细而精确的答案!这似乎是解决我的问题的方法。 – Klaus

+0

这与瑞士发条一样有效! ;-) 非常感谢Martin(也提供了上面代码中calloc的bpp问题提示)! – Klaus