fff*_*fff 3 alpha image-processing ios swift
我的 CVPixelBuffer 为kCVPixelFormatType_32BGRA,我试图获取没有 Alpha 通道的 BGR 格式的帧数据。这是我尝试做的(作为extension CVPixelBuffer
)
func bgrData(byteCount: Int) -> Data? {
CVPixelBufferLockBaseAddress(self, .readOnly)
defer { CVPixelBufferUnlockBaseAddress(self, .readOnly) }
guard let sourceData = CVPixelBufferGetBaseAddress(self) else {
return nil
}
let width = CVPixelBufferGetWidth(self)
let height = CVPixelBufferGetHeight(self)
let sourceBytesPerRow = CVPixelBufferGetBytesPerRow(self)
let destinationBytesPerRow = 3 * width
// Assign input image to `sourceBuffer` to convert it.
var sourceBuffer = vImage_Buffer(
data: sourceData,
height: vImagePixelCount(height),
width: vImagePixelCount(width),
rowBytes: sourceBytesPerRow
)
// Make `destinationBuffer` and `destinationData` for its data to be assigned.
guard let destinationData = malloc(height * destinationBytesPerRow) else {
os_log("Error: out of memory", type: .error)
return nil
}
defer { free(destinationData) }
var destinationBuffer = vImage_Buffer(
data: destinationData,
height: vImagePixelCount(height),
width: vImagePixelCount(width),
rowBytes: destinationBytesPerRow)
// Return `Data` with bgr image.
return imageByteData = Data(
bytes: sourceBuffer.data, count: destinationBuffer.rowBytes * height)
}
Run Code Online (Sandbox Code Playgroud)
但获得的缓冲区似乎不正确。实现这一目标的最佳方法是什么?提前致谢
由于您可以访问 CVPixelBuffer,因此您可以直接使用 Accelerate 框架来为您进行转换。
我不会检查此代码中的任何错误、try/catch 语句、无防护等。您需要确保代码是防错的。
让我们首先定义 BGRA 颜色格式。由于我们有 4 个通道,因此每个像素需要 32 位。我们还定义我们的 Alpha 通道是最后一位。
var bgraSourceFormat = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: Unmanaged.passRetained(CGColorSpaceCreateDeviceRGB()),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue),
version: 0,
decode: nil,
renderingIntent: .defaultIntent
)
Run Code Online (Sandbox Code Playgroud)
现在我们可以定义 BGR 格式。我们需要 3 个通道,因此每像素 24 位就足够了。我们还定义该格式不会有 Alpha 通道。
var bgrDestinationFormat = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 24,
colorSpace: nil,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
version: 0,
decode: nil,
renderingIntent: .defaultIntent
)
Run Code Online (Sandbox Code Playgroud)
并创建转换器...
let bgraToRgbConverter = vImageConverter_CreateWithCGImageFormat(
&bgraSourceFormat,
&bgrDestinationFormat,
nil,
vImage_Flags(kvImagePrintDiagnosticsToConsole),
nil
)
let converter = bgraToRgbConverter!.takeRetainedValue()
Run Code Online (Sandbox Code Playgroud)
现在我们需要从现有的像素数据创建一个读取缓冲区,以及一个用于复制我们需要的数据的写入缓冲区。要从 CVPixelBuffer 创建读取缓冲区,我们可以执行以下操作:
var bgraBuffer = vImage_Buffer()
let imageFormat = vImageCVImageFormat_CreateWithCVPixelBuffer(cvPixelBuffer).takeRetainedValue()
vImageCVImageFormat_SetColorSpace(imageFormat, CGColorSpaceCreateDeviceRGB())
vImageBuffer_InitWithCVPixelBuffer(
&bgraBuffer,
&bgraSourceFormat,
cvPixelBuffer,
imageFormat,
nil,
vImage_Flags(kvImageNoFlags)
)
Run Code Online (Sandbox Code Playgroud)
并创建空的写入缓冲区...
var bgrBuffer = vImage_Buffer()
vImageBuffer_Init(
&bgrBuffer,
bgraBuffer.height,
bgraBuffer.width,
bgrDestinationFormat.bitsPerPixel,
vImage_Flags(kvImageNoFlags)
)
Run Code Online (Sandbox Code Playgroud)
我们准备好了...让我们告诉加速框架从一种格式转换为另一种格式
vImageConvert_AnyToAny(
converter,
&bgraBuffer,
&bgrBuffer,
nil,
vImage_Flags(kvImagePrintDiagnosticsToConsole)
)
Run Code Online (Sandbox Code Playgroud)
就这样。您的 BGRA 现已转换为 BGR 作为vImage_Buffer
. 我们可以通过直接读取像素数据来检查是否达到了我们想要的效果。首先,我们需要访问数据:
let bgraData = bgraBuffer.data!.assumingMemoryBound(to: UInt8.self)
let bgrData = bgrBuffer.data!.assumingMemoryBound(to: UInt8.self)
Run Code Online (Sandbox Code Playgroud)
现在,我们可以打印第一个和第二个像素
print(bgraData[0], bgraData[1], bgraData[2], bgraData[3])
print(bgrData[0], bgrData[1], bgrData[2])
print(bgraData[4], bgraData[5], bgraData[6], bgraData[7])
print(bgrData[3], bgrData[4], bgrData[5])
Run Code Online (Sandbox Code Playgroud)
这是我在游乐场中用于测试的 png 图像中看到的输出:
249 244 234 255
249 244 234
251 242 233 255
251 242 233
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,像素是在没有 Alpha 通道的情况下复制的。如果您要使用 for 循环,请小心,因为我们现在有 3 个通道。
如果您正在开发游戏并在每个帧上执行此操作,请尝试保持对象处于活动状态。加速格式定义,写入缓冲区和转换器对于相同的图像大小和格式永远不会改变,因此它们可以创建一次并保存在内存中以供将来使用。
看起来您正在返回一个数据对象。您可以将UnsafeMutablePointer
构造转换为您需要的任何内容。
或者您也可以vImage_Buffer
使用加速方法转换回 CVPixelBuffer(如果需要)vImageBuffer_CopyToCVPixelBuffer
。vImage_Buffer
有很多转换器,绝对能满足您的需求。检查此链接以获取有关如何使用复制到像素缓冲区方法的更多信息。这个链接有一个很好的用法示例。
编辑:您的 CVPixelBuffer 可能已填充。
由于硬件要求,您的图像可能有填充,以确保缓冲区宽度和高度是 16 的倍数。这也会导致结构中出现填充vImage_Buffer
。如果您需要循环,但只需要访问/更新单个像素,您可以使用 Accelerate 的函数来提高速度。检查此链接以了解可能的方法,页面末尾有很好的示例。
要完整读取数据,您可以编写如下内容:
249 244 234 255
249 244 234
251 242 233 255
251 242 233
Run Code Online (Sandbox Code Playgroud)
这将确保您读取全宽像素,但在末尾传递填充。
归档时间: |
|
查看次数: |
1379 次 |
最近记录: |