【问题标题】:Getting the red intensity of every frame of video capture IOS获取每帧视频捕获IOS的红色强度
【发布时间】: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


【解决方案1】:

感谢您找到了另一种解决方案,但作为参考,我相信这会奏效:

- (float) processPixelBuffer:(CVPixelBufferRef) pixelBuffer{
  CVPixelBufferLockBaseAddress(pixelBuffer, 0);
  size_t pixelWidth = CVPixelBufferGetWidth(pixelBuffer);
  size_t pixelHeight = CVPixelBufferGetHeight(pixelBuffer);
  size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
  uint8_t *sourceBuffer = (uint8_t*)CVPixelBufferGetBaseAddress(pixelBuffer);
  CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
  int bufferSize = bytesPerRow * height;
  uint8_t *pixels = malloc(bufferSize);
  memcpy(pixels, sourceBuffer, bufferSize);      
  int totalRedPixelWeight = 0;
  for (int i = 0; i < pixelHeight; i++) {
    for (int ii = 0; ii < pixelWidth; ii+=4) {
      int redLoc = (bufferHeight * i) + ii + 2;
      totalRedPixelWeight += pixels[redLoc];
    }
  }
  free (pixels);
  float meanRedPixelWeight = totalRedPixelWeight/(pixelWidth*pixelHeight);
  NSLog(@"%f",meanRedPixelWeight);
  return meanRedPixelWeight;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 1970-01-01
    相关资源
    最近更新 更多