在 swift 中使用 vImageHistogramCalculation 计算图像的直方图

Posted

技术标签:

【中文标题】在 swift 中使用 vImageHistogramCalculation 计算图像的直方图【英文标题】:Compute the histogram of an image using vImageHistogramCalculation in swift 【发布时间】:2015-03-09 18:56:53 【问题描述】:

我正在尝试使用 Accelerate vImageHistogramCalculation_ARGBFFFF 函数计算图像的直方图,但我得到了 vImage_Error 类型的 kvImageNullPointerArgument(错误代码为 -21772)。

这是完全相同的问题,但我正在使用 Swift:Compute the histogram of an image using vImageHistogramCalculation

    // Get CGImage from UIImage
    var image:UIImage = UIImage(named: "happiness1")!
    var img:CGImageRef = image.CGImage

    // Create vImage_Buffer with data from CGImageRef
    var inProvider:CGDataProviderRef = CGImageGetDataProvider(img)
    var inBitmapData:CFDataRef = CGDataProviderCopyData(inProvider)

    // The next three lines set up the inBuffer object
    var height:vImagePixelCount = CGImageGetHeight(img)
    var width:vImagePixelCount = CGImageGetWidth(img)
    var rowBytes:UInt = CGImageGetBytesPerRow(img)
    var data:UnsafePointer<Void> = UnsafePointer<Void>(CFDataGetBytePtr(inBitmapData))

    // Setup inBuffer
    var inBuffer = vImage_Buffer(data: &data, height: height, width: width, rowBytes: rowBytes)

    var histogram_entries:UInt32 = 4
    var minVal:Pixel_F = 0
    var maxVal:Pixel_F = 255
    //let flags:vImage_Flags = kvImageNoFlags = 0

    var histogram = UnsafeMutablePointer<UnsafeMutablePointer<vImagePixelCount>>()

    var error:vImage_Error = vImageHistogramCalculation_ARGBFFFF(&inBuffer, histogram, histogram_entries, minVal, maxVal, 0)

    println(error)

问题出在直方图变量中,我需要重新创建这样的东西:

// create an array of four histograms with eight entries each.
vImagePixelCount histogram[4][8] = 0;  
// vImageHistogramCalculation requires an array of pointers to the histograms.
vImagePixelCount *histogramPointers[4] =  &histogram[0][0], &histogram[1][0], &histogram[2][0], &histogram[3][0] ;
vImage_Error error = vImageHistogramCalculation_ARGBFFFF(&inBuffer, histogramPointers, 8, 0, 255, kvImageNoFlags);
// You can now access bin j of the histogram for channel i as histogram[i][j].
// The storage for the histogram will be cleaned up when execution leaves the
// current lexical block.

建议?

【问题讨论】:

是的,从 vImage 的角度来看,这就是您需要做的。唉,不能帮助 Swift 结束。如果最终的解决方案足够神秘,Apple 可能会受益于一个错误,即从 Swift 调用这是一个特别具有挑战性的接口。我应该补充一点,很少有图像格式会自然生成 32 位浮点数作为其原始图像格式。浮动-tiff,也许。如果你想控制你从 CGImage 中得到什么图像格式,你应该使用 vImageBuffer_InitWithCGImage()。 此外,除了少数例外(L* a* b* 浮动图像),浮动图像的范围通常为 [0,1] 而不是 [0,255]。 【参考方案1】:

我已经将 vImageHistogramCalculation_ARGB8888 实现为 Swift 中 UIImage 的扩展:

 func SIHistogramCalculation() -> (alpha: [UInt], red: [UInt], green: [UInt], blue: [UInt]) 
   let imageRef = self.CGImage
   let inProvider = CGImageGetDataProvider(imageRef)
   let inBitmapData = CGDataProviderCopyData(inProvider)

   var inBuffer = vImage_Buffer(data: UnsafeMutablePointer(CFDataGetBytePtr(inBitmapData)), height: UInt(CGImageGetHeight(imageRef)), width: UInt(CGImageGetWidth(imageRef)), rowBytes: CGImageGetBytesPerRow(imageRef))

   var alpha = [UInt](count: 256, repeatedValue: 0)
   var red = [UInt](count: 256, repeatedValue: 0)
   var green = [UInt](count: 256, repeatedValue: 0)
   var blue = [UInt](count: 256, repeatedValue: 0)

   var alphaPtr = UnsafeMutablePointer<vImagePixelCount>(alpha)
   var redPtr = UnsafeMutablePointer<vImagePixelCount>(red)
   var greenPtr = UnsafeMutablePointer<vImagePixelCount>(green)
   var bluePtr = UnsafeMutablePointer<vImagePixelCount> (blue)

   var rgba = [redPtr, greenPtr, bluePtr, alphaPtr]

   var histogram = UnsafeMutablePointer<UnsafeMutablePointer<vImagePixelCount>>(rgba)
   var error = vImageHistogramCalculation_ARGB8888(&inBuffer, histogram, UInt32(kvImageNoFlags))
   return (alpha, red, green, blue)
 

(取自https://github.com/FlexMonkey/ShinpuruImage)

【讨论】:

这不再在 Xcode 8、Swift 3 中编译,出现错误:“无法将 'UnsafeMutablePointer>' (又名 'UnsafeMutablePointer>') 类型的值转换为预期参数类型 'UnsafeMutablePointer?>'(又名 'UnsafeMutablePointer>>')” 行:var rgba = [redPtr, greenPtr, bluePtr, alphaPtr] 应该是 var rgba = [alphaPtr, redPtr, greenPtr, bluePtr] 在 XCode 5 中,要绕过 UnsafeMutablePointer 警告,请使用 withUnsafeMutableBufferPoint,如 Apple 的本页所示:developer.apple.com/documentation/accelerate/…【参考方案2】:

对于 Swift 5,您需要明确让编译器知道您的指针是可选的。将您的 UnsafeMutablePointer 声明更改为以下内容:

Swift 5 版本:

let redPtr = red.withUnsafeMutableBufferPointer  $0.baseAddress 
let greenPtr = green.withUnsafeMutableBufferPointer  $0.baseAddress 
let bluePtr = blue.withUnsafeMutableBufferPointer  $0.baseAddress 
let alphaPtr = alphaChannel.withUnsafeMutableBufferPointer  $0.baseAddress 
let histogram = UnsafeMutablePointer<UnsafeMutablePointer<vImagePixelCount>?>.allocate(capacity: 4)

histogram[0] = redPtr
histogram[1] = greenPtr
histogram[2] = bluePtr
histogram[3] = alphaPtr
let error:vImage_Error = vImageHistogramCalculation_ARGB8888(&inBuffer, histogram, UInt32(kvImageNoFlags))

Swift 4 版本:

let redPtr: UnsafeMutablePointer<vImagePixelCount>? = UnsafeMutablePointer(mutating: red)
let greenPtr: UnsafeMutablePointer<vImagePixelCount>? = UnsafeMutablePointer(mutating:green)
let bluePtr: UnsafeMutablePointer<vImagePixelCount>? = UnsafeMutablePointer(mutating:blue)
let alphaPtr: UnsafeMutablePointer<vImagePixelCount>? = UnsafeMutablePointer(mutating:alpha)

【讨论】:

在 Swift 5 上,这会给出警告。 “UnsafeMutablePointer”(又名“UnsafeMutablePointer”)的初始化会导致指针悬空 @Gizmodo Swift 5 在上面添加。 histogram[0] = redPtr 的行中,我收到Expression type '()' is ambiguous without more context 错误 你的“红色”缓冲区是不是像这样:var red = [UInt](repeating: 0, count: 256) 啊——withUnsafeMutableBufferPointer 调用应该返回指针 ($0.baseAddress)。我已经在上面修复了。【参考方案3】:

今天,我编写代码来分析照片的 RGB 直方图。它现在正在工作。

func getHistogram(_ image: UIImage) ->  (alpha: [UInt], red: [UInt], green: [UInt], blue: [UInt]) 
    
        guard
            let cgImage = image.cgImage,
            var imageBuffer = try? vImage_Buffer(cgImage: cgImage)
        else 
            return nil
        
        defer 
            imageBuffer.free()
        

        var redArray: [vImagePixelCount] = Array(repeating: 0, count: 256)
        var greenArray: [vImagePixelCount] = Array(repeating: 0, count: 256)
        var blueArray: [vImagePixelCount] = Array(repeating: 0, count: 256)
        var alphaArray: [vImagePixelCount] = Array(repeating: 0, count: 256)
        var error: vImage_Error = kvImageNoError

        redArray.withUnsafeMutableBufferPointer  rPointer in
            greenArray.withUnsafeMutableBufferPointer  gPointer in
                blueArray.withUnsafeMutableBufferPointer  bPointer in
                    alphaArray.withUnsafeMutableBufferPointer  aPointer in

            var histogram = [ rPointer.baseAddress, gPointer.baseAddress, bPointer.baseAddress, aPointer.baseAddress ]
            histogram.withUnsafeMutableBufferPointer  hPointer in
              
              if let hBaseAddress = hPointer.baseAddress 
                
                error = vImageHistogramCalculation_ARGB8888(&imageBuffer, hBaseAddress, vNoFlags)
                            
                        
                    
                
            
        

        guard error == kvImageNoError else 
            printVImageError(error: error)
            return nil
        
        
  
        return (alphaArray, redArray, greenArray, blueArrat)
    

【讨论】:

以上是关于在 swift 中使用 vImageHistogramCalculation 计算图像的直方图的主要内容,如果未能解决你的问题,请参考以下文章

swift 优雅地处理Swift中可本地化的字符串。注意:此代码在Swift 2中,需要在现代Swift中使用更新。

在 Swift 项目中使用 Objective C 类中的 Swift 类

在 Swift 项目中使用 Objective C 类中的 Swift 类

如何在 Swift 中使用 Apple 地图 - 你必须使用 C 还是 Swift 可以?

swift 在swift中使用javascriptcore

swift 在swift中使用枚举练习