How can I extract the data from the output image of CIAreaHistogramFilter

I would like to get arrays of red, green and blue histogram data from the output of the CIAreaHistogramFilter. My current approach is not working.

According to the docs CIAreaHistogramFilter returns an image with width = bin size (256) in my case and height = 1
so each pixel contains the count of the rgb values for that bin.

Code Block
if let areahistogram = self.areaHistogramFilter(ciImage) {
let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary
var pixelBuffer : CVPixelBuffer?
let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(areahistogram.extent.size.width), Int(areahistogram.extent.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer)
guard (status == kCVReturnSuccess) else {
return
}
self.hContext.render(areahistogram, to: pixelBuffer!)
CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0));
let int32Buffer = unsafeBitCast(CVPixelBufferGetBaseAddress(pixelBuffer!), to: UnsafeMutablePointer<UInt32>.self)
let int32PerRow = CVPixelBufferGetBytesPerRow(pixelBuffer!)
var data = [Int]()
for i in 0..<256 {
/* Get BGRA value for pixels */
let BGRA = int32Buffer[i]
data.append(Int(BGRA))
let red = (BGRA >> 16) & 0xFF;
let green = (BGRA >> 8) & 0xFF;
let blue = BGRA & 0xFF;
os_log("data[\(i)]:\(BGRA) red: \(red) green: \(green) blue: \(blue)")
}
CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
}

results in zeros.

Code Block
data[0]:0 red: 0 green: 0 blue: 0
data[1]:0 red: 0 green: 0 blue: 0
...
data[255]:134678783 red: 7 green: 7 blue: 7


similarly produces a bunch of zeros

or this

Code Block
let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer!)
let buffer = baseAddress!.assumingMemoryBound(to: UInt8.self)
for i in stride(from: 0, to: 256*4, by: 4) {
let blue = buffer[i]
let green = buffer[i+1]
let red = buffer[i+2]
os_log("data[\(i)]: red: \(red) green: \(green) blue: \(blue)")
}


or this variation that seems simpler

Code Block
var red = [UInt8]()
            var green = [UInt8]()
            var blue = [UInt8]()
            for i in 0..<256 {
                // Get BGRA value for pixel
                let BGRA = int32Buffer[i]
                withUnsafeBytes(of: BGRA.bigEndian) {
                    red.append($0[0])
                    green.append($0[1])
                    blue.append($0[2])
                }
        }

Replies

I don't exactly know why you are getting all zeros here, but there is a much simpler way to access the data using CIContext.render(_:toBitmap:...).
Please check out the implementation in this small helper package I wrote that contains useful Core Image extensions.
Thanks @FrankSchlegel - I will try it out.