通过 vImage 提取图像通道有副作用
Extracting image channels via vImage comes with side effect
我正在尝试使用 vImageConvert_ARGB8888toPlanar8
API to extract RGB channels. Suppose the following inputImage
is a solid white image from: https://www.solidbackgrounds.com/images/1080x1920/1080x1920-white-solid-color-background.jpg
这是我的代码:
let inputImage = #imageLiteral(resourceName: "1080x1920-white-solid-color-background.jpg")
guard let sourceCGImage = inputImage.cgImage,
let sourceImageFormat = vImage_CGImageFormat(cgImage: sourceCGImage),
var sourceImageBuffer = try? vImage_Buffer(cgImage: sourceCGImage,
format: sourceImageFormat) else {
fatalError()
}
let componentCount = sourceImageFormat.componentCount
var argbSourcePlanarBuffers: [vImage_Buffer] = (0..<componentCount).map { _ in
let bitsPerPixel = UInt32(8)
guard let buffer = try? vImage_Buffer(width: Int(sourceImageBuffer.width),
height: Int(sourceImageBuffer.height),
bitsPerPixel: bitsPerPixel) else {
fatalError("Error creating planar buffers.")
}
return buffer
}
vImageConvert_ARGB8888toPlanar8(&sourceImageBuffer,
&argbSourcePlanarBuffers[0], // R
&argbSourcePlanarBuffers[1], // G
&argbSourcePlanarBuffers[2], // B
&argbSourcePlanarBuffers[3], // A
vImage_Flags(kvImageNoFlags))
print("Image H: \(sourceCGImage.height), W: \(sourceCGImage.width)")
let capacity = sourceCGImage.width * sourceCGImage.height
print("capacity: \(capacity)")
// Repeat the following code for other 3 channels
let channelDataPtrR = argbSourcePlanarBuffers[0].data.bindMemory(to: Pixel_8.self,
capacity: capacity)
let channelRawDataR = UnsafeBufferPointer(start: channelDataPtrR, count: capacity)
let channelDataR = Array(channelRawDataR)
var histogramR = [Double](repeating: 0.0, count: 255 + 1)
channelDataR.map { histogramR[Int([=10=])] += 1.0 }
print("histogramR:")
for (i, px) in histogramR.enumerated() {
if px > 0.0 {
print("Pixel Val \(i): \(px)")
}
}
这是我得到的:
Image H: 1920, W: 1080
capacity: 2073600
histogramR:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
histogramG:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
histogramB:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
histogramA:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
问题:如果图像应该是纯白色(即所有像素值 = 255?),我怎么会得到像素值 0
?
另请注意,如果我 运行 上面的代码使用 Xcode 的模拟器,我会得到不同数量的 Pixel Val 0
,但总数 capacity
仍然是 2073600
.
这可能是因为缓冲区的实际行字节比图像宽(请参阅 Finding the Sharpest Image in a Sequence of Captured Images 中的 Create Floating Point Pixels to Use in vDSP 以获得解释行字节如何超出图像的边界框)。
如果您使用 Specifying Histograms with vImage 中的代码,您应该得到您期望的值:
var histogramBinZero = [vImagePixelCount](repeating: 0, count: 256)
var histogramBinOne = [vImagePixelCount](repeating: 0, count: 256)
var histogramBinTwo = [vImagePixelCount](repeating: 0, count: 256)
var histogramBinThree = [vImagePixelCount](repeating: 0, count: 256)
histogramBinZero.withUnsafeMutableBufferPointer { zeroPtr in
histogramBinOne.withUnsafeMutableBufferPointer { onePtr in
histogramBinTwo.withUnsafeMutableBufferPointer { twoPtr in
histogramBinThree.withUnsafeMutableBufferPointer { threePtr in
var histogramBins = [zeroPtr.baseAddress, onePtr.baseAddress,
twoPtr.baseAddress, threePtr.baseAddress]
histogramBins.withUnsafeMutableBufferPointer { histogramBinsPtr in
let error = vImageHistogramCalculation_ARGB8888(&sourceImageBuffer,
histogramBinsPtr.baseAddress!,
vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else {
fatalError("Error calculating histogram: \(error)")
}
}
}
}
}
}
for (i, px) in histogramBinTwo.enumerated() {
if px > 0 {
print("Pixel Val \(i): \(px)")
}
}
我正在尝试使用 vImageConvert_ARGB8888toPlanar8
API to extract RGB channels. Suppose the following inputImage
is a solid white image from: https://www.solidbackgrounds.com/images/1080x1920/1080x1920-white-solid-color-background.jpg
这是我的代码:
let inputImage = #imageLiteral(resourceName: "1080x1920-white-solid-color-background.jpg")
guard let sourceCGImage = inputImage.cgImage,
let sourceImageFormat = vImage_CGImageFormat(cgImage: sourceCGImage),
var sourceImageBuffer = try? vImage_Buffer(cgImage: sourceCGImage,
format: sourceImageFormat) else {
fatalError()
}
let componentCount = sourceImageFormat.componentCount
var argbSourcePlanarBuffers: [vImage_Buffer] = (0..<componentCount).map { _ in
let bitsPerPixel = UInt32(8)
guard let buffer = try? vImage_Buffer(width: Int(sourceImageBuffer.width),
height: Int(sourceImageBuffer.height),
bitsPerPixel: bitsPerPixel) else {
fatalError("Error creating planar buffers.")
}
return buffer
}
vImageConvert_ARGB8888toPlanar8(&sourceImageBuffer,
&argbSourcePlanarBuffers[0], // R
&argbSourcePlanarBuffers[1], // G
&argbSourcePlanarBuffers[2], // B
&argbSourcePlanarBuffers[3], // A
vImage_Flags(kvImageNoFlags))
print("Image H: \(sourceCGImage.height), W: \(sourceCGImage.width)")
let capacity = sourceCGImage.width * sourceCGImage.height
print("capacity: \(capacity)")
// Repeat the following code for other 3 channels
let channelDataPtrR = argbSourcePlanarBuffers[0].data.bindMemory(to: Pixel_8.self,
capacity: capacity)
let channelRawDataR = UnsafeBufferPointer(start: channelDataPtrR, count: capacity)
let channelDataR = Array(channelRawDataR)
var histogramR = [Double](repeating: 0.0, count: 255 + 1)
channelDataR.map { histogramR[Int([=10=])] += 1.0 }
print("histogramR:")
for (i, px) in histogramR.enumerated() {
if px > 0.0 {
print("Pixel Val \(i): \(px)")
}
}
这是我得到的:
Image H: 1920, W: 1080
capacity: 2073600
histogramR:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
histogramG:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
histogramB:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
histogramA:
Pixel Val 0: 129600.0
Pixel Val 255: 1944000.0
问题:如果图像应该是纯白色(即所有像素值 = 255?),我怎么会得到像素值 0
?
另请注意,如果我 运行 上面的代码使用 Xcode 的模拟器,我会得到不同数量的 Pixel Val 0
,但总数 capacity
仍然是 2073600
.
这可能是因为缓冲区的实际行字节比图像宽(请参阅 Finding the Sharpest Image in a Sequence of Captured Images 中的 Create Floating Point Pixels to Use in vDSP 以获得解释行字节如何超出图像的边界框)。
如果您使用 Specifying Histograms with vImage 中的代码,您应该得到您期望的值:
var histogramBinZero = [vImagePixelCount](repeating: 0, count: 256)
var histogramBinOne = [vImagePixelCount](repeating: 0, count: 256)
var histogramBinTwo = [vImagePixelCount](repeating: 0, count: 256)
var histogramBinThree = [vImagePixelCount](repeating: 0, count: 256)
histogramBinZero.withUnsafeMutableBufferPointer { zeroPtr in
histogramBinOne.withUnsafeMutableBufferPointer { onePtr in
histogramBinTwo.withUnsafeMutableBufferPointer { twoPtr in
histogramBinThree.withUnsafeMutableBufferPointer { threePtr in
var histogramBins = [zeroPtr.baseAddress, onePtr.baseAddress,
twoPtr.baseAddress, threePtr.baseAddress]
histogramBins.withUnsafeMutableBufferPointer { histogramBinsPtr in
let error = vImageHistogramCalculation_ARGB8888(&sourceImageBuffer,
histogramBinsPtr.baseAddress!,
vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else {
fatalError("Error calculating histogram: \(error)")
}
}
}
}
}
}
for (i, px) in histogramBinTwo.enumerated() {
if px > 0 {
print("Pixel Val \(i): \(px)")
}
}