【发布时间】:2014-03-25 21:58:26
【问题描述】:
好的,我正在处理这个项目。任务是使用 iPhone/Ipad 摄像头测量心率。我正在尝试使用 AVFoundation 捕获视频,获取每一帧并将帧中每个像素的红色分量相加,然后将其除以大小以获得平均值。
我先设置视频
-(void) setupAVCapture{
_session = [[AVCaptureSession alloc] init];
_session.sessionPreset = AVCaptureSessionPresetMedium;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!error) {
if ([device lockForConfiguration:&error]) {
if ([device hasTorch] && [device isTorchModeSupported:AVCaptureTorchModeOn]) {
[device setTorchMode:AVCaptureTorchModeOn];
}
[device unlockForConfiguration];
}
if ( [_session canAddInput:input] )
[_session addInput:input];
AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new];
[videoDataOutput setVideoSettings:@{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) }];
[videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];
dispatch_queue_t videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
[videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue];
if ( [_session canAddOutput:videoDataOutput] )
[_session addOutput:videoDataOutput];
[_session startRunning];
}
else{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"Failed with error %d", (int)[error code]] message:[error localizedDescription] delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[alertView show];
}
}
然后使用委托方法如下 -
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{
// got an image
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
//redScores property is an array which stores the red values of all the frames
[self.redScores addObject: [NSNumber numberWithFloat:[self processPixelBuffer:pixelBuffer]]];
}
-(float) processPixelBuffer:(CVPixelBufferRef) pixelBuffer{
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
size_t bufferWidth = CVPixelBufferGetWidth(pixelBuffer);
size_t bufferHeight = CVPixelBufferGetHeight(pixelBuffer);
unsigned char *pixels = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBuffer);
int meanRedPixelWeight=0.0;
for (int i = 0; i < (bufferWidth * bufferHeight); i++) {
meanRedPixelWeight += pixels[2];
}
meanRedPixelWeight=meanRedPixelWeight/(bufferWidth*bufferHeight);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
NSLog(@"%d",meanRedPixelWeight);
return meanRedPixelWeight;
}
但这似乎没有给我正确的红色值。一方面,我看到价值不断下降。它应该是上升和下降。其次,我拍摄了视频并在 matlab 中进行了类似处理 -
v=VideoReader('filepath');
noOfFrames = v.NumberOfFrames;
x=zeros(1,numFrames);
for i=1:noOfFrames,
frame = read(v,1);
redPlane = frame(:, :, 1);
x(i) = sum(sum(redPlane)) / (size(frame, 1) * size(frame, 2));
我得到非常不同的平均值。 matlab 的接近 255,因此我可以判断它们是正确的,因为所有帧几乎都是红色的。
关于 Objective-c 代码有什么问题有什么想法吗?
【问题讨论】:
-
我可以提个建议吗?如果您使用我的框架:github.com/BradLarson/GPUImage 并将来自 GPUImageVideoCamera 的输出输入到 GPUImageAverageColor 操作中,您可以避免编写任何代码。这将为您提供一个回调块,它将在每个视频帧进入时为您提供平均红色、绿色和蓝色值。它也是 GPU 加速的,因此速度非常快。
-
你在简历上比我深得多,所以我不会有太多帮助,但是 (a) 你为什么要取消参考像素[2]?是 alpha 优先吗?(b)我使用了 Brad Larson 的 GPUImage,它很有帮助。谢谢@BradLarson!
-
非常感谢@BradLarson。我使用 GPUImage 实现了它。它似乎工作正常。虽然我注意到一个问题,但平均红色值似乎总是下降。它从 254 开始,并以 ~0.01 的步幅持续下降。到达 230 后我停了下来。
-
@danh - 我认为 alpha 是像素[3]。
-
@user3461705 - iOS 相机总是会尝试校正白平衡和亮度,所以我认为你不能自己依赖红色值。其他人使用红/蓝比率或交叉,或转换为 HSV 颜色空间以消除亮度变化的影响:stackoverflow.com/questions/19773631/…
标签: ios iphone objective-c avfoundation video-processing