如何从iPhone相机进行快速图像处理?

gru*_*htr 12 iphone camera avfoundation ios

我正在尝试编写一个iPhone应用程序,它将进行一些实时的相机图像处理.我使用AVFoundation文档中提供的示例作为起点:设置捕获会话,从示例缓冲区数据创建UIImage,然后在一个点上绘制图像-setNeedsDisplay,我在主线程上调用.

这是有效的,但它相当慢(每帧50毫秒,在-drawRect:调用之间测量,对于192 x 144预设)我已经看到App Store上的应用程序比这更快.
我大约一半的时间都花在了-setNeedsDisplay.

如何加快图像处理速度?

Bra*_*son 21

史蒂夫指出,在我的回答中,我鼓励人们在从iPhone的相机处理图像并将图像渲染到屏幕时,查看OpenGL ES以获得最佳性能.原因是使用Quartz不断将UIImage更新到屏幕上是将原始像素数据发送到显示器的一种相当慢的方法.

如果可能的话,我建议您查看OpenGL ES来进行实际处理,因为GPU的调整方式非常适合这类工作.如果您需要保持OpenGL ES 1.1的兼容性,那么您的处理选项比使用2.0的可编程着色器更受限制,但您仍然可以进行一些基本的图像调整.

即使您使用CPU上的原始数据进行所有图像处理,通过对图像数据使用OpenGL ES纹理,每帧更新一次,您仍然会更好.只需切换到渲染路线,您就会看到性能的提升.

(更新:2012年2月18日)正如我在上述链接答案的更新中描述的那样,我使用新的开源GPUImage框架使这个过程变得更加容易.它可以为您处理所有OpenGL ES交互,因此您可以专注于在传入视频上应用过滤器和其他效果.它使用CPU绑定例程和手动显示更新比使用此处理快5-70倍.


pra*_*epa 5

将sessionPresent的捕获会话设置为AVCaptureSessionPresetLow,如下面的示例代码所示,这将提高处理速度,但缓冲区中的图像质量较差.



- (void)initCapture {
    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput 
                                          deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] 
                                          error:nil];
    AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init] ;
    captureOutput.alwaysDiscardsLateVideoFrames = YES; 
    captureOutput.minFrameDuration = CMTimeMake(1, 25);
    dispatch_queue_t queue;
    queue = dispatch_queue_create("cameraQueue", NULL);
    [captureOutput setSampleBufferDelegate:self queue:queue];
    dispatch_release(queue);
    NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey; 
    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; 
    NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key]; 
    [captureOutput setVideoSettings:videoSettings]; 
    self.captureSession = [[AVCaptureSession alloc] init] ;
    [self.captureSession addInput:captureInput];
    [self.captureSession addOutput:captureOutput];
    self.captureSession.sessionPreset=AVCaptureSessionPresetLow;
    /*sessionPresent choose appropriate value to get desired speed*/

    if (!self.prevLayer) {
        self.prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
    }
    self.prevLayer.frame = self.view.bounds;
    self.prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer: self.prevLayer];

}