使用摄像头检测心率

28
我需要与应用程式 Instant Heart Rate 相同的功能。基本过程需要用户执行以下步骤:
  1. 轻轻将食指尖放在摄像头镜头上。
  2. 均匀施加压力并覆盖整个镜头。
  3. 保持稳定10秒钟并获取心率。
通过打开闪光灯并观察血液通过食指移动时光线变化即可实现这一过程。
如何从视频捕获中获取光线水平数据?我该在哪里寻找?
我查看了类 AVCaptureDevice 但没有找到有用的东西。
我还发现 AVCaptureDeviceSubjectAreaDidChangeNotification,那会有用吗?

但是对于iPhone和iPad的非Flash型号呢? - The iOSDev
@AalokParikh:如果你的环境光线足够明亮,手机闪光灯就不是必需品了。 - alinoz
@alinoz 这款相机应用程序需要闪光灯,否则你只会看到黑暗,因为手指会挡住镜头。 - occulus
@occoulus,我不确定使用iPhone相机的工作方式,但是如果环境光线足够充足,使用普通网络摄像头时就不需要额外的光源。 - alinoz
@TheLion 当光线不足时,将您的移动设备举起来(同时将手指放在设备的相机上),并将其靠近明亮的光源:对我而言,这在窗户透过的阳光下有效。 - Developer Marius Žilėnas
3个回答

27

看一下这个...

// switch on the flash in torch mode  
 if([camera isTorchModeSupported:AVCaptureTorchModeOn]) {  
 [camera lockForConfiguration:nil];  
 camera.torchMode=AVCaptureTorchModeOn;  
 [camera unlockForConfiguration];  
 }  

  [session setSessionPreset:AVCaptureSessionPresetLow];

   // Create the AVCapture Session  
   session = [[AVCaptureSession alloc] init];  

  // Get the default camera device  
   AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];  
  if([camera isTorchModeSupported:AVCaptureTorchModeOn]) {  
    [camera lockForConfiguration:nil];  
  camera.torchMode=AVCaptureTorchModeOn;  
    [camera unlockForConfiguration];  
 }  
 // Create a AVCaptureInput with the camera device  
    NSError *error=nil;  
     AVCaptureInput* cameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:camera error:&error];  
   if (cameraInput == nil) {  
    NSLog(@"Error to create camera capture:%@",error);  
  }  

    // Set the output  
    AVCaptureVideoDataOutput* videoOutput = [[AVCaptureVideoDataOutput alloc] init];  

   // create a queue to run the capture on  
  dispatch_queue_t captureQueue=dispatch_queue_create("catpureQueue", NULL);  

   // setup our delegate  
   [videoOutput setSampleBufferDelegate:self queue:captureQueue];  

    // configure the pixel format  
    videoOutput.videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber     numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey,  
     nil];  
   // cap the framerate  
   videoOutput.minFrameDuration=CMTimeMake(1, 10);  
  // and the size of the frames we want  
  [session setSessionPreset:AVCaptureSessionPresetLow];  

   // Add the input and output  
   [session addInput:cameraInput];  
   [session addOutput:videoOutput];  

   // Start the session  

    [session startRunning];  

   - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {  



   // this is the image buffer  

  CVImageBufferRef cvimgRef = CMSampleBufferGetImageBuffer(sampleBuffer);  


   // Lock the image buffer  

  CVPixelBufferLockBaseAddress(cvimgRef,0);  


  // access the data  

  int width=CVPixelBufferGetWidth(cvimgRef);  
  int height=CVPixelBufferGetHeight(cvimgRef);  


  // get the raw image bytes  
  uint8_t *buf=(uint8_t *) CVPixelBufferGetBaseAddress(cvimgRef);  
  size_t bprow=CVPixelBufferGetBytesPerRow(cvimgRef);  


// get the average red green and blue values from the image  

 float r=0,g=0,b=0;  
 for(int y=0; y<height; y++) {  
 for(int x=0; x<width*4; x+=4) {  
  b+=buf[x];  
  g+=buf[x+1];  
  r+=buf[x+2];  
 }  
 buf+=bprow;  
 }  
  r/=255*(float) (width*height);  
  g/=255*(float) (width*height);  
  b/=255*(float) (width*height);  

  NSLog(@"%f,%f,%f", r, g, b);  
  }  

示例代码 这里


3
这段代码只提供图表,但是获取心率值(如100bpm)背后的逻辑是什么?你有什么想法吗? - coder1010
1
嗨,示例代码的链接不存在了,你能再次发布一下示例代码吗? - Vijay Patidar

3

顺便提一下,您可能会对这篇研究论文感兴趣。此方法甚至不需要手指(或任何东西)直接放在镜头上。


3
那篇文章是一项正在申请专利的研究,如果这对你有所影响的话。 - user23987
你能提供它是否已被专利或正在申请专利的参考文献吗? - AlexK

3
实际上很简单,你需要分析捕获图像的像素值。一个简单的算法是:选择图像中心的区域,转换为灰度,获取每个图像像素的中位数,然后你将得到一个二维函数,在这个函数上计算两个最小值或最大值之间的距离,问题解决了。
如果你观察在5秒内获取的图像的直方图,你会注意到灰度级别分布的变化。如果你想要更稳健的计算结果,请分析直方图。

2
嗨alinoz,你能否发布一些示例代码?先感谢了! - Brabbeldas
@AT_AB和Brabbeldas - 我会尝试在接下来的几天内制作一个小型设置。 - alinoz
1
@alinoz - 你有机会放一个这个的示例项目/代码吗?如果你做了什么,请告诉我们。 - Sam B
@allinoz,我不明白在找到两个最小值或最大值之间的距离后问题是如何解决的,你能否详细说明一下? - kkk
@kkk 使用每个捕获图像的时间戳。 - alinoz
根据算法,我需要计算每个帧的中位数,然后取最大(或最小)的两个中位数值及其出现时间,然后计算心率,是吗?@alinoz - kkk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接