使用Swift中的vImageHistogramCalculation计算图像的直方图

4
我正在尝试使用Accelerate的vImageHistogramCalculation_ARGBFFFF函数计算图像的直方图,但是我得到了一个类型为kvImageNullPointerArgumentvImage_Error错误(错误代码为-21772)。
这是完全相同的问题,但我正在使用Swift:使用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的问题。如果最终解决方案足够复杂,苹果可能会受益于一个报告错误,称这是一个特别具有挑战性的接口,难以从Swift中调用。我应该补充说,很少有图像格式自然地产生32位浮点作为其原始图像格式。也许是Float-tiff。如果你想控制从CGImage输出的图像格式,你应该使用vImageBuffer_InitWithCGImage()。 - Ian Ollmann
此外,除了 L* a* b* 浮点图像之外,浮点图像通常的范围是 [0,1] 而不是 [0,255]。 - Ian Ollmann
3个回答

6
我已经使用以下代码将 vImageHistogramCalculation_ARGB8888 作为 UIImage 的扩展在 Swift 中实现了:
 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

该项目旨在将IT技术与图像处理融合,通过使用Go编写的RESTful API,提供简单易用的图像转换服务。ShinpuruImage支持一系列常见的图像操作,包括大小调整、裁剪和过滤器。此外,该项目还提供了API文档和代码示例,以方便开发者快速上手。

在Xcode 8,Swift 3中,此代码已无法编译,会出现以下错误:"Cannot convert value of type 'UnsafeMutablePointer<UnsafeMutablePointer<vImagePixelCount>>' (aka 'UnsafeMutablePointer<UnsafeMutablePointer<UInt>>') to expected argument type 'UnsafeMutablePointer<UnsafeMutablePointer<vImagePixelCount>?>' (aka 'UnsafeMutablePointer<Optional<UnsafeMutablePointer<UInt>>>')" - jbaraga
该行代码应该修改为: var rgba = [alphaPtr, redPtr, greenPtr, bluePtr] - Bill Chan
在XCode 5中,为了避免UnsafeMutablePointer警告,请使用Apple页面上显示的withUnsafeMutableBufferPoint:https://developer.apple.com/documentation/accelerate/specifying_histograms_with_vimage - Rethunk

3

针对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
1
@Gizmodo Swift 5 已添加。 - fargofargofargo
1
你的“红色”缓冲区是否像这样:var red = [UInt](repeating: 0, count: 256) - fargofargofargo
var red = [vImagePixelCount](repeating: 0, count: 256) - Gizmodo
1
啊——withUnsafeMutableBufferPointer调用应该返回指针($0.baseAddress),我已经在上面修复了它。 - fargofargofargo
显示剩余2条评论

0
今天,我编写了分析照片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)
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接