我怎样才能从iPhone相机快速处理图像?
我正在写一个iPhone应用程序,它将做一些实时的相机image processing。 我使用AVFoundation文档中提供的示例作为出发点:设置捕获会话,从样本缓冲区数据制作UIImage,然后通过-setNeedsDisplay
(在主线程中调用)绘制图像。
这是有效的,但速度相当慢(每帧50毫秒,在-drawRect:
调用之间测量,对于192 x 144预设),而且我在App Store上看到的应用程序比这更快。
大约一半的时间都花在-setNeedsDisplay
。
我怎样才能加快这个image processing?
正如Steve指出的那样,在我的回答中,我鼓励人们在使用iPhone相机处理和渲染图像到屏幕上时,最好的性能是看OpenGL ES。 原因是使用Quartz来不断地将UIImage更新到屏幕上是一种相当慢的将原始像素数据发送到显示器的方法。
如果可能的话,我鼓励你看看OpenGL ES做你的实际处理,因为这种工作的GPU是多么好调整。 如果您需要保持OpenGL ES 1.1的兼容性,那么您的处理选项比2.0的可编程着色器更有限,但是您仍然可以进行一些基本的图像调整。
即使使用CPU上的原始数据进行所有image processing,对于图像数据使用OpenGL ES纹理,也可以通过每帧更新。 只要切换到渲染路线,您就会看到性能的飞跃。
(更新:2012年2月18日)正如我在上面链接的答案的更新中所描述的那样,我使用新的开放源代码GPUImage框架使得这个过程变得更加简单。 这将为您处理所有的OpenGL ES交互,所以您可以专注于在传入的video中应用您想要的滤镜和其他效果。 它比用CPU限制例程和手动显示更新进行这种处理的速度快5-70倍。
如下面的示例代码所示,将捕获会话的sessionPresent设置为AVCaptureSessionPresetLow,这将提高处理速度,但来自缓冲区的图像质量较差。
- (void)initCapture { AVCaptureDeviceInput * captureInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] 误差:无]; AVCaptureVideoDataOutput * captureOutput = [[AVCaptureVideoDataOutput alloc] init]; captureOutput.alwaysDiscardsLateVideoFrames = YES; captureOutput.minFrameDuration = CMTimeMake(1,25); dispatch_queue_t队列 queue = dispatch_queue_create(“cameraQueue”,NULL); [captureOutput setSampleBufferDelegate:self queue:queue]; dispatch_release(队列); 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; / * sessionPresentselect合适的值来获得所需的速度* / 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]; }