用 iOS 中的白色像素替换部分像素缓冲区
Replace Part of Pixel Buffer with White Pixels in iOS
我正在使用 iPhone 摄像头捕捉实时视频,并将像素缓冲区提供给进行某些对象识别的网络。这是相关代码:(我不会post设置AVCaptureSession
的代码
等等,因为这是非常标准的。)
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
OSType sourcePixelFormat = CVPixelBufferGetPixelFormatType( pixelBuffer );
int doReverseChannels;
if ( kCVPixelFormatType_32ARGB == sourcePixelFormat ) {
doReverseChannels = 1;
} else if ( kCVPixelFormatType_32BGRA == sourcePixelFormat ) {
doReverseChannels = 0;
} else {
assert(false);
}
const int sourceRowBytes = (int)CVPixelBufferGetBytesPerRow( pixelBuffer );
const int width = (int)CVPixelBufferGetWidth( pixelBuffer );
const int fullHeight = (int)CVPixelBufferGetHeight( pixelBuffer );
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
unsigned char* sourceBaseAddr = CVPixelBufferGetBaseAddress( pixelBuffer );
int height;
unsigned char* sourceStartAddr;
if (fullHeight <= width) {
height = fullHeight;
sourceStartAddr = sourceBaseAddr;
} else {
height = width;
const int marginY = ((fullHeight - width) / 2);
sourceStartAddr = (sourceBaseAddr + (marginY * sourceRowBytes));
}
}
然后网络将 sourceStartAddr
、width
、height
、sourceRowBytes
和 doReverseChannels
作为输入。
我的问题如下:什么是最简单and/or最有效的替换或删除部分全白图像数据的方法'pixels'?是否可以直接覆盖像素缓冲区数据的 e 部分,如果是,如何?
我对这个像素缓冲区的工作原理只有非常初步的了解,所以如果我在这里遗漏了一些非常基本的东西,我深表歉意。我在 Whosebug 上发现的与我最相关的问题是 this one,其中 EAGLContext
用于向视频帧添加文本。虽然这实际上适用于我的 objective,它只需要替换单个图像,但我认为如果应用于每个视频帧,此步骤会降低性能,我想知道是否有另一种方法。如有任何帮助,我们将不胜感激。
这是一种无需使用 Core Graphics 或 OpenGL 等其他库即可操作 CVPixelBufferRef
的简单方法:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
const int kBytesPerPixel = 4;
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
int bufferWidth = (int)CVPixelBufferGetWidth( pixelBuffer );
int bufferHeight = (int)CVPixelBufferGetHeight( pixelBuffer );
size_t bytesPerRow = CVPixelBufferGetBytesPerRow( pixelBuffer );
uint8_t *baseAddress = CVPixelBufferGetBaseAddress( pixelBuffer );
for ( int row = 0; row < bufferHeight; row++ )
{
uint8_t *pixel = baseAddress + row * bytesPerRow;
for ( int column = 0; column < bufferWidth; column++ )
{
if ((row < 100) && (column < 100) {
pixel[0] = 255; // BGRA, Blue value
pixel[1] = 255; // Green value
pixel[2] = 255; // Red value
}
pixel += kBytesPerPixel;
}
}
CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
// Do whatever needs to be done with the pixel buffer
}
这会用白色像素覆盖图像中左上角的 100 x 100 像素块。
我在这个名为 RosyWriter 的 Apple Developer Example 中找到了这个解决方案。
有点惊讶,考虑到事实证明这是多么容易,我在这里没有得到任何答案。希望这对某人有所帮助。
使用 Swift 实施更新它。
CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
let bufferWidth = Int(CVPixelBufferGetWidth(pixelBuffer))
let bufferHeight = Int(CVPixelBufferGetHeight(pixelBuffer))
let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
guard let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer) else {
return
}
for row in 0..<bufferHeight {
var pixel = baseAddress + row * bytesPerRow
for col in 0..<bufferWidth {
let blue = pixel
blue.storeBytes(of: 255, as: UInt8.self)
let red = pixel + 1
red.storeBytes(of: 255, as: UInt8.self)
let green = pixel + 2
green.storeBytes(of: 255, as: UInt8.self)
let alpha = pixel + 3
alpha.storeBytes(of: 255, as: UInt8.self)
pixel += 4;
}
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
由于baseAddress
给出了不支持下标的UnsafeMutableRawPointer
,所以你必须改用storeBytes
。这基本上是与上述 Objective-C 版本的唯一关键区别。
我必须使用 captureOutput 和 CVPixelBuffer 处理来自 iPhone 相机的帧。我使用您的代码(谢谢!)在像素缓冲区中以每秒 15 帧的速度循环播放大约 20 万像素,但我经常遇到丢帧问题。事实证明,在 Swift 中,while
循环比 for ... in
循环快 10 倍。
喜欢:
0.09 秒:
for row in 0..<bufferHeight {
for col in 0..<bufferWidth {
// process pixels
0.01 秒:
var x = 0
var y = 0
while y < bufferHeight
{
y += 1
x = 0;
while x < bufferWidth
{
// process pixels
}
}
我正在使用 iPhone 摄像头捕捉实时视频,并将像素缓冲区提供给进行某些对象识别的网络。这是相关代码:(我不会post设置AVCaptureSession
的代码
等等,因为这是非常标准的。)
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
OSType sourcePixelFormat = CVPixelBufferGetPixelFormatType( pixelBuffer );
int doReverseChannels;
if ( kCVPixelFormatType_32ARGB == sourcePixelFormat ) {
doReverseChannels = 1;
} else if ( kCVPixelFormatType_32BGRA == sourcePixelFormat ) {
doReverseChannels = 0;
} else {
assert(false);
}
const int sourceRowBytes = (int)CVPixelBufferGetBytesPerRow( pixelBuffer );
const int width = (int)CVPixelBufferGetWidth( pixelBuffer );
const int fullHeight = (int)CVPixelBufferGetHeight( pixelBuffer );
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
unsigned char* sourceBaseAddr = CVPixelBufferGetBaseAddress( pixelBuffer );
int height;
unsigned char* sourceStartAddr;
if (fullHeight <= width) {
height = fullHeight;
sourceStartAddr = sourceBaseAddr;
} else {
height = width;
const int marginY = ((fullHeight - width) / 2);
sourceStartAddr = (sourceBaseAddr + (marginY * sourceRowBytes));
}
}
然后网络将 sourceStartAddr
、width
、height
、sourceRowBytes
和 doReverseChannels
作为输入。
我的问题如下:什么是最简单and/or最有效的替换或删除部分全白图像数据的方法'pixels'?是否可以直接覆盖像素缓冲区数据的 e 部分,如果是,如何?
我对这个像素缓冲区的工作原理只有非常初步的了解,所以如果我在这里遗漏了一些非常基本的东西,我深表歉意。我在 Whosebug 上发现的与我最相关的问题是 this one,其中 EAGLContext
用于向视频帧添加文本。虽然这实际上适用于我的 objective,它只需要替换单个图像,但我认为如果应用于每个视频帧,此步骤会降低性能,我想知道是否有另一种方法。如有任何帮助,我们将不胜感激。
这是一种无需使用 Core Graphics 或 OpenGL 等其他库即可操作 CVPixelBufferRef
的简单方法:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
const int kBytesPerPixel = 4;
CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
int bufferWidth = (int)CVPixelBufferGetWidth( pixelBuffer );
int bufferHeight = (int)CVPixelBufferGetHeight( pixelBuffer );
size_t bytesPerRow = CVPixelBufferGetBytesPerRow( pixelBuffer );
uint8_t *baseAddress = CVPixelBufferGetBaseAddress( pixelBuffer );
for ( int row = 0; row < bufferHeight; row++ )
{
uint8_t *pixel = baseAddress + row * bytesPerRow;
for ( int column = 0; column < bufferWidth; column++ )
{
if ((row < 100) && (column < 100) {
pixel[0] = 255; // BGRA, Blue value
pixel[1] = 255; // Green value
pixel[2] = 255; // Red value
}
pixel += kBytesPerPixel;
}
}
CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
// Do whatever needs to be done with the pixel buffer
}
这会用白色像素覆盖图像中左上角的 100 x 100 像素块。
我在这个名为 RosyWriter 的 Apple Developer Example 中找到了这个解决方案。
有点惊讶,考虑到事实证明这是多么容易,我在这里没有得到任何答案。希望这对某人有所帮助。
使用 Swift 实施更新它。
CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
let bufferWidth = Int(CVPixelBufferGetWidth(pixelBuffer))
let bufferHeight = Int(CVPixelBufferGetHeight(pixelBuffer))
let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
guard let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer) else {
return
}
for row in 0..<bufferHeight {
var pixel = baseAddress + row * bytesPerRow
for col in 0..<bufferWidth {
let blue = pixel
blue.storeBytes(of: 255, as: UInt8.self)
let red = pixel + 1
red.storeBytes(of: 255, as: UInt8.self)
let green = pixel + 2
green.storeBytes(of: 255, as: UInt8.self)
let alpha = pixel + 3
alpha.storeBytes(of: 255, as: UInt8.self)
pixel += 4;
}
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
由于baseAddress
给出了不支持下标的UnsafeMutableRawPointer
,所以你必须改用storeBytes
。这基本上是与上述 Objective-C 版本的唯一关键区别。
我必须使用 captureOutput 和 CVPixelBuffer 处理来自 iPhone 相机的帧。我使用您的代码(谢谢!)在像素缓冲区中以每秒 15 帧的速度循环播放大约 20 万像素,但我经常遇到丢帧问题。事实证明,在 Swift 中,while
循环比 for ... in
循环快 10 倍。
喜欢:
0.09 秒:
for row in 0..<bufferHeight {
for col in 0..<bufferWidth {
// process pixels
0.01 秒:
var x = 0
var y = 0
while y < bufferHeight
{
y += 1
x = 0;
while x < bufferWidth
{
// process pixels
}
}