8

我正在尝试在 iPhone 上进行一些图像处理。我正在使用http://developer.apple.com/library/ios/#qa/qa2010/qa1702.html来捕获相机帧。

我的问题是,当我尝试访问捕获的缓冲区时,相机 FPS 从 30 下降到大约 20。有人知道我该如何解决吗?

我使用了我能找到的最低捕获质量(AVCaptureSessionPresetLow = 192x144),采用 kCVPixelFormatType_32BGRA 格式。如果有人知道我可以使用的较低质量,我愿意尝试。

当我在其他平台(如 Symbian)上进行相同的图像访问时,它工作正常。

这是我的代码:

#pragma mark -
#pragma mark AVCaptureSession delegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
    fromConnection:(AVCaptureConnection *)connection 
{ 
 /*We create an autorelease pool because as we are not in the main_queue our code is
  not executed in the main thread. So we have to create an autorelease pool for the thread we are in*/
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
 //Lock the image buffer
    if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess)
    {  

  // calculate FPS and display it using main thread
  [self performSelectorOnMainThread:@selector(updateFps:) withObject: (id) nil waitUntilDone:NO];


  UInt8 *base = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); //image buffer start address

  size_t width  = CVPixelBufferGetWidth(imageBuffer); 
  size_t height = CVPixelBufferGetHeight(imageBuffer);

  int size = (height*width);
  UInt8* pRGBtmp = m_pRGBimage;

        /*
        Here is the problem; m_pRGBimage is RGB image I want to process.
        In the 'for' loop I convert the image from BGRA to RGB. As a resault, the FPS drops to 20.
        */ 
  for (int i=0;i<size;i++)
  {   
    pRGBtmp[0] = base[2];
    pRGBtmp[1] = base[1];
    pRGBtmp[2] = base[0];
    base = base+4;
    pRGBtmp = pRGBtmp+3;     
  }


  // Display received action
  [self performSelectorOnMainThread:@selector(displayAction:) withObject: (id) nil waitUntilDone:NO];
  //[self displayAction:&eyePlayOutput];
  //saveFrame( imageBuffer );

  //unlock the  image buffer
  CVPixelBufferUnlockBaseAddress(imageBuffer,0);

 }


 [pool drain];
} 

作为答案的后续,我需要实时处理图像,它正在显示。

我注意到当我使用 AVCaptureSessionPresetHigh 时,我做的最简单的事情是:

 for (int i=0;i<size;i++)
    x = base[0];

导致帧率下降到 4-5 FPS。我猜是因为没有缓存该大小的图像。

基本上我需要 96x48 图像。有没有一种简单的方法来缩小相机输出图像,一种使用硬件加速的方法,所以我可以使用小的方法?

4

3 回答 3

8

除了最快的 iOS 设备外,任何迭代图像中每个像素的东西都会相当慢。例如,我通过简单的每像素颜色测试对 640 x 480 视频帧(307,200 像素)中的每个像素进行了基准测试,发现这仅在 iPhone 4 上以 4 FPS 左右的速度运行。

您正在考虑在您的情况下处理 27,648 像素,它的运行速度应该足以在 iPhone 4 上达到 30 FPS,但这比原始 iPhone 和 iPhone 3G 中的处理器要快得多。iPhone 3G 可能仍会与这种处理负载作斗争。你也没有说处理器在你的 Symbian 设备中有多快。

我建议重新设计您的处理算法以避免色彩空间转换。应该不需要重新排序颜色组件来处理它们。

此外,您可以通过在图像的行和列中以特定间隔采样来选择性地仅处理几个像素。

最后,如果您的目标是支持 OpenGL ES 2.0 的较新 iOS 设备(iPhone 3GS 和更新版本),您可能需要考虑使用 GLSL 片段着色器来完全在 GPU 上处理视频帧。我在这里描述了这个过程,以及基于颜色的实时对象跟踪的示例代码。在我的基准测试中,GPU 处理这种处理的速度比 CPU 快 14 到 28 倍。

于 2010-11-23T19:53:25.123 回答
1

免责声明:这个答案是猜测:)

当缓冲区被锁定时,你做了很多工作;这是否阻止了从相机捕获图像的线程?

您可以在处理数据时将数据从缓冲区中复制出来,以便尽快解锁它,例如

if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess) {
    // Get the base address and size of the buffer
    UInt8 *buffer_base = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); //image buffer start address
    size_t width  = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer);

    // Copy it's contents out
    Uint8 *base = malloc(width * height * 4);
    memcpy(base, buffer_base, size);

    // Unlock the buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    // base now points to a copy of the buffers' data - do what you want to it . . .
    ...

    // remember to free base once you're done ;)
    free(base);

如果是锁阻止了捕获,那么这应该会有所帮助。

注意 如果您知道所有缓冲区的大小相同,则可以加快速度,您可以调用一次 malloc 来获取内存,然后每次都重用它,只有在处理完所有缓冲区后才释放它。


或者,如果这不是问题,您可以尝试降低此线程的优先级

[NSThread setThreadPriority:0.25];
于 2010-11-23T13:29:00.500 回答
0

将相机帧的内容复制到专用缓冲区并从那里对其进行操作。这在我的经验中导致了巨大的速度提高。我最好的猜测是相机框架所在的内存区域有特殊的保护,使读/写访问变慢。

查看相机帧数据的内存地址。在我的设备上,相机缓冲区位于0x63ac000. 这对我来说没有任何意义,只是其他堆对象的地址更接近0x1300000. 锁定建议并没有解决我的减速问题,但memcpy确实解决了。

于 2010-12-08T12:22:54.977 回答