2015-10-04 75 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

相關問題