本文介绍了iOS的心率检测算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我想实现一个应用程序我开发的心脏跳动录制功能。

I'm trying to implement heart beat recording functionality in an app i'm developing.

这样做的preferred方法是通过使用iPhone的相机上的光中,具有用户将他们的手指放在透镜和视频馈送,其对应于用户的心脏中检测的波动。

The preferred method of doing this is by using the iPhone's camera with the light on, having the user place their finger on the lens, and detecting fluctuations in the video feed, which correspond to the user's heart.

我发现下面的堆栈溢出问题一个非常好的起点这里

I found a very good starting point with the following stack overflow questionhere

问题提供了有益的code绘制一个心脏搏动时间图。

The question provides useful code to plot a heart beat time graph.

它显示了如何开始AVCaptureSession并打开相机的亮像这样:

It shows how to start an AVCaptureSession and turn the camera's light on like so:

session = [[AVCaptureSession alloc] init];

AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if([camera isTorchModeSupported:AVCaptureTorchModeOn]) {
    [camera lockForConfiguration:nil];
    camera.torchMode=AVCaptureTorchModeOn;
    //  camera.exposureMode=AVCaptureExposureModeLocked;
    [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];
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];

自我在这个例子中必须是< AVCaptureVideoDataOutputSampleBufferDelegate> 因此,也就有了实现下面的方法来获得原始相机数据:

Self in this example must be an <AVCaptureVideoDataOutputSampleBufferDelegate>And will therefore have to implement the following method to obtain raw camera data:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
static int count=0;
count++;
// only run if we're not already processing an image
// 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);
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];
        //          a+=buf[x+3];
    }
    buf+=bprow;
}
r/=255*(float) (width*height);
g/=255*(float) (width*height);
b/=255*(float) (width*height);

float h,s,v;

RGBtoHSV(r, g, b, &h, &s, &v);

// simple highpass and lowpass filter

static float lastH=0;
float highPassValue=h-lastH;
lastH=h;
float lastHighPassValue=0;
float lowPassValue=(lastHighPassValue+highPassValue)/2;

lastHighPassValue=highPassValue;

    //low pass value can now be used for basic heart beat detection


}

RGB转换到HSV并且它是被监测的波动色相

RGB is converted to HSV and it is Hue that is monitored for fluctuations.

和RGB到HSV的实现如下

And RGB to HSV is implemented as follows

void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v ) {
float min, max, delta;
min = MIN( r, MIN(g, b ));
max = MAX( r, MAX(g, b ));
*v = max;
delta = max - min;
if( max != 0 )
    *s = delta / max;
else {
    // r = g = b = 0
    *s = 0;
    *h = -1;
    return;
}
if( r == max )
    *h = ( g - b ) / delta;
else if( g == max )
    *h=2+(b-r)/delta;
else
    *h=4+(r-g)/delta;
*h *= 60;
if( *h < 0 )
    *h += 360;
}

低通在计算值capureOutput:最初提供的数据飘忽不定,但随后企稳于以下内容:

The low pass value calculated in capureOutput: initially provides erratic data, but then stabilises to the following:

2013-11-04 16:18:13.619 SampleHeartRateApp[1743:1803] -0.071218
2013-11-04 16:18:13.719 SampleHeartRateApp[1743:1803] -0.050072
2013-11-04 16:18:13.819 SampleHeartRateApp[1743:1803] -0.011375
2013-11-04 16:18:13.918 SampleHeartRateApp[1743:1803] 0.018456
2013-11-04 16:18:14.019 SampleHeartRateApp[1743:1803] 0.059024
2013-11-04 16:18:14.118 SampleHeartRateApp[1743:1803] 0.052198
2013-11-04 16:18:14.219 SampleHeartRateApp[1743:1803] 0.078189
2013-11-04 16:18:14.318 SampleHeartRateApp[1743:1803] 0.046035
2013-11-04 16:18:14.419 SampleHeartRateApp[1743:1803] -0.113153
2013-11-04 16:18:14.519 SampleHeartRateApp[1743:1803] -0.079792
2013-11-04 16:18:14.618 SampleHeartRateApp[1743:1803] -0.027654
2013-11-04 16:18:14.719 SampleHeartRateApp[1743:1803] -0.017288

最初提供的数据不稳定的一个例子是在这里:

An example of the erratic data provided initially is here:

2013-11-04 16:17:28.747 SampleHeartRateApp[1743:3707] 17.271435
2013-11-04 16:17:28.822 SampleHeartRateApp[1743:1803] -0.049067
2013-11-04 16:17:28.922 SampleHeartRateApp[1743:1803] -6.524201
2013-11-04 16:17:29.022 SampleHeartRateApp[1743:1803] -0.766260
2013-11-04 16:17:29.137 SampleHeartRateApp[1743:3707] 9.956407
2013-11-04 16:17:29.221 SampleHeartRateApp[1743:1803] 0.076244
2013-11-04 16:17:29.321 SampleHeartRateApp[1743:1803] -1.049292
2013-11-04 16:17:29.422 SampleHeartRateApp[1743:1803] 0.088634
2013-11-04 16:17:29.522 SampleHeartRateApp[1743:1803] -1.035559
2013-11-04 16:17:29.621 SampleHeartRateApp[1743:1803] 0.019196
2013-11-04 16:17:29.719 SampleHeartRateApp[1743:1803] -1.027754
2013-11-04 16:17:29.821 SampleHeartRateApp[1743:1803] 0.045803
2013-11-04 16:17:29.922 SampleHeartRateApp[1743:1803] -0.857693
2013-11-04 16:17:30.021 SampleHeartRateApp[1743:1803] 0.061945
2013-11-04 16:17:30.143 SampleHeartRateApp[1743:1803] -0.701269

低通值变正,每当有一个心脏的跳动。所以,我想一个很简单的现场检测算法基本上着眼于当前值,并认为如果是积极的,它也着眼于previous值,如果为负检测负向正,起到了提示音。

The low pass value goes positive whenever there is a heart beat. So I tried a very simple live detection algorithm which basically looks at the current value, and sees if it is positive, it also looks at the previous value, if negative it detects negative going to positive and plays a beep sound.

这里的问题是数据并不总是完美的,因为上面,有时有异常积极的读数之间的负读数,反之亦然。

The problem with this is the data isn't always as perfect as the above, sometimes there's anomalous positive readings in amongst negative readings and vice versa.

在时间的低通值的曲线图如下所示:

A graph of the low pass value in time looks like this:

有趣的是,上述异常现象是相当普遍的,如果我录制图有一段时间我会看到一个非常类似的形状异常多次。

Interestingly the above anomaly is quite common, if I record a graph for a while i'll see a very similar shaped anomaly multiple times.

在我的非常简单的拍子检测算法中,如果如上述所示的异常发生在检测期间节拍的计数(10秒)可以由4或5次直线上升。这使得所计算的BPM非常不准确的。但作为简单的,因为它是它解决了70%的时间。

In my very simple beat detection algorithm, if an anomaly as shown above occurs the counted number of beats in the detection period (10 seconds) can shoot up by 4 or 5 beats. This makes the calculated BPM very inaccurate. But as simple as it is it does work around 70% of the time.

要解决这个问题我尝试以下。

To combat this problem I tried the following.

1.Started阵列中的记录最后3低通值

1.Started recording last 3 low pass values in an array

2.Then期待看的中间值是否有前后周围两个较小的值。 (基本峰值检测)

2.Then looked to see whether or not the middle value had two smaller values surrounding it before and after. (Basic peak detection)

3.Counted这种情况下作为一个节拍和加入到运转的总节拍在给定的时间。

3.Counted this scenario as a beat and added it to the running total of beats in a given time.

这方法却一样容易受到异常任何其他。而实际上似乎是一个更糟糕的方法。 (当检测后,现场演出的哔哔声,他们似乎远远超过了正到负的算法更不稳定)

This method is however just as vulnerable to the anomalies as any other. And actually seemed to be a worse method. (When playing live beeps after detection they seemed far more erratic than the positive to negative algorithm)

我的问题是,你能不能帮我想出了一个算法,当心脏跳动时以合理的精度,能够可靠地检测。

还有一个问题我知道我要去有解决的是检测用户的手指是否在镜头上。

Another problem I realise that i'm going to have to address is detecting whether or not a user's finger is on the lens.

我想到了检测不稳定的低通值,但问题有低通滤波器占了错误的值和平滑出来一段时间。因此,帮助就不会有pciated太AP $ P $。

I thought about detecting erratic low pass values but the problem there is the low pass filter accounts for erratic values and smooths them out over time. So help there would be appreciated too.

感谢您的时间。

推荐答案

在这个问题的答案是一点点参与其中,因为你需要做几件事情来处理信号,并没有单一的正确的方式做本。但是,对于您的过滤器要使用带通滤波器。这种类型的过滤器允许您指定一个范围,在高端和低端都接受两种频率。对于一个人的心脏跳动,我们知道这些界限应该是(不低于40 BPM和不高于250 BPM),因此我们可以创建一个消除了这个范围以外的频率的过滤器。过滤器也移动数据以在零为中心,所以峰值检测变得更加容易。该过滤器会给你一个更平稳的信号,即使用户增加/减少他们的手指pressure(在一定程度上)。在此之后,额外的平滑和异常值去除也需要发生

The answer to this question is a little bit involved, as you need to do several things to process the signal and there is no single "right" way to do this. However, for your filter you want to use a band-pass filter. This type of filter allows you to specify a range of frequencies that are accepted both at the high and low ends. For a human heart beat, we know what these bounds should be (no less than 40 bpm and no higher than 250 bpm) so we can create a filter that removes frequencies outside of this range. The filter also moves the data to be centered at zero, so peak detection becomes much easier. This filter will give you a much more smooth signal, even if your users increases/decreases their finger pressure (to a certain degree). After that, additional smoothing and outlier removal will also need to happen.

带通滤波器,我已经使用特定类型的巴特沃斯滤波器。这是一个小参与手工,因为根据你是在收集数据的频率更换过滤器来创建。幸运的是,有一个网站,可以帮助此这里。如果你是在每秒30帧收集数据,则频率为30赫兹。

A specific type of band-pass filter that I have used is a butterworth filter. This is a little involved to create by hand since the filter changes based on the frequency you are collecting your data at. Fortunately, there is a website that can help with this here. If you are collecting your data at 30 fps, then the frequency will be 30 hz.

我已经创建了一个包装了这一切在一起,并检测用户的心脏率不够好,包括它在我的iOS应用商店的应用程序的项目。我做了心脏速率检测code,适用于 github上

I have created a project that wraps all of this together and detects a user's heart rate well enough to include it in my app on the iOS app store. I have made the heart rate detection code available on github.

这篇关于iOS的心率检测算法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 07:08