Подтвердить что ты не робот

IOS Алгоритм определения частоты сердечных сокращений

Я пытаюсь реализовать функцию записи сердечного ритма в приложении, которое я разрабатываю.

Предпочтительный способ сделать это - использовать камеру iPhone с подсветкой, если пользователь поместит палец на объектив и обнаружил колебания в видеопотоке, которые соответствуют сердцу пользователя.

Я нашел очень хорошую отправную точку со следующим вопросом здесь

Вопрос предоставляет полезный код для построения графика времени сердечного ритма.

Показывает, как запустить AVCaptureSession и включить подсветку камеры следующим образом:

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> И поэтому для получения необработанных данных камеры необходимо реализовать следующий метод:

- (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, и Hue отслеживается для колебаний.

И RGB для HSV реализуется следующим образом

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:, первоначально предоставляет неустойчивые данные, но затем стабилизируется до следующего значения:

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

Пример непредвиденных данных, представленных на начальном этапе:

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

Значение нижнего прохода становится положительным, когда есть сердечный ритм. Поэтому я пробовал очень простой алгоритм обнаружения в реальном времени, который в основном рассматривает текущее значение и видит, что он положительный, он также смотрит на предыдущее значение, если отрицательное значение отрицательно влияет на положительный и воспроизводит звуковой сигнал.

Проблема с этим заключается в том, что данные не всегда такие же совершенные, как выше, иногда есть аномальные положительные показания среди отрицательных чтений и наоборот.

График значения низкого прохода во времени выглядит следующим образом: enter image description here

Интересно, что вышеупомянутая аномалия довольно распространена, если я запишу график на некоторое время, я увижу очень похожую фазовую аномалию несколько раз.

В моем очень простом алгоритме обнаружения биений, если появляется аномалия, как показано выше, подсчитанное количество ударов в период обнаружения (10 секунд) может стрелять на 4 или 5 ударов. Это делает расчетный BPM очень неточным. Но так просто, как будто он работает примерно в 70% случаев.

Чтобы справиться с этой проблемой, я попробовал следующее.

1. Запущена запись последних 3 значений нижних частот в массиве

2. Затем он посмотрел, имеет ли среднее значение два меньших значения, окружающие его до и после. (Обнаружение основного пика)

3.Установил этот сценарий как бит и добавил его к общему количеству битов в заданное время.

Этот метод, однако, так же уязвим для аномалий, как и любой другой. И на самом деле это был худший метод. (При воспроизведении живых звуковых сигналов после обнаружения они казались гораздо более неустойчивыми, чем положительный отрицательный алгоритм)

Мой вопрос: можете ли вы помочь мне придумать алгоритм, который может надежно обнаруживать, когда сердечный ритм происходит с разумной точностью.

Еще одна проблема, которую я понимаю, что мне нужно адресовать, - это определить, находится ли пользовательский палец на объективе.

Я думал об обнаружении ошибочных значений нижних частот, но проблема в том, что фильтр нижних частот учитывает неустойчивые значения и сглаживает их со временем. Поэтому помощь тоже будет оценена.

Спасибо за ваше время.

4b9b3361

Ответ 1

Ответ на этот вопрос немного задействован, так как вам нужно сделать несколько действий для обработки сигнала, и нет единого "правильного" способа сделать это. Однако для вашего фильтра вы хотите использовать полосовой фильтр. Этот тип фильтра позволяет указать диапазон частот, которые принимаются как на высоких, так и на низких концах. Для человеческого сердечного ритма мы знаем, какими должны быть эти ограничения (не менее 40 уд/мин и не более 250 уд/мин), поэтому мы можем создать фильтр, который удаляет частоты за пределами этого диапазона. Фильтр также перемещает данные в центр с нулевым значением, поэтому обнаружение пиков становится намного проще. Этот фильтр даст вам гораздо более плавный сигнал, даже если ваши пользователи увеличивают/уменьшают давление пальцев (в определенной степени). После этого также потребуется дополнительное сглаживание и удаление выделения.

Конкретный тип полосового фильтра, который я использовал, является фильтром масляного фильтра. Это немного связано с созданием вручную, поскольку фильтр изменяется в зависимости от частоты, с которой вы собираете данные. К счастью, есть сайт, который может помочь с этим здесь. Если вы собираете данные со скоростью 30 кадров в секунду, частота будет 30 Гц.

Я создал проект, который объединяет все это вместе и достаточно хорошо определяет частоту сердечных сокращений пользователя, чтобы включить его в мое приложение в магазине приложений iOS. Я сделал код обнаружения сердечного ритма на github.

Ответ 2

Я полагаю, вы используете свой собственный палец. Вы уверены, что у вас нет нерегулярного биения? Кроме того, вам нужно будет обращаться с людьми с нерегулярными сердечными сокращениями.. Другими словами, вы должны протестировать с помощью самых разных входных значений. Определенно попробуйте это у своих родителей или других старших родственников, так как у них могут быть более серьезные проблемы с сердцем. Помимо этого, ваша основная проблема заключается в том, что ваш источник ввода будет шумным; вы в основном пытаетесь восстановить сигнал от этого шума. Иногда это будет невозможно, и вам придется решить, хотите ли вы испечь шум в своем отчете или просто игнорировать поток данных, когда он слишком шумный.

Продолжайте пробовать различные значения фильтра; может быть, вам нужен фильтр нижних частот. Из комментариев это звучит так, как ваш фильтр нижних частот не был хорош; там тонны ресурсов на фильтрацию там в сети. Если у вас есть хорошие инструменты визуализации, которые будут лучшим способом протестировать ваш алгоритм.

Вы можете попробовать выполнить выборку данных, что позволит сгладить ее. Вы также можете захотеть отбросить образцы, которые лежат вне допустимого диапазона, либо полностью отменив это значение, заменив его на среднее значение предыдущего и следующего образца, и/или закрепив его до некоторого предопределенного или рассчитанный максимум.

Моя самая большая говядина с такими приложениями заключается в том, что икоты рассматриваются как реальные, живые данные. Один из байков в моем тренажерном зале дает бесполезные показания bpm, потому что, каждый так часто, он не может найти мой пульс и вдруг думает, что мое сердце идет со скоростью 300 уд/мин. (Который это не так, я спросил у своего врача.) Для 20-минутной сессии среднее значение имеет бесполезное. Я думаю, что более полезно видеть среднее значение (например,) последних десяти нормальных ударов плюс коэффициент аномалии, а не "Я пытался запихнуть последние 20 секунд в этот алгоритм, а тут вывалился мусор". Если вы можете создать отдельный фильтр, который указывает на аномалии, я думаю, у вас будет гораздо более полезное приложение.

Ответ 3

Похоже, что у вас уже есть другой метод, но вы можете попытаться использовать небольшой средний фильтр. Например, при использовании медианы, скажем, от 3 до 7 входных значений для каждого выходного значения сглаживают эти пики, не разрушая общую форму не аномальных данных.

Ответ 4

Вы пытаетесь обнаружить один сердечный ритм "вручную", который не будет очень надежным. Я бы сказал, что ваш лучший выбор - это нечто вроде библиотеки определения высоты тона или частоты (математика для определения частоты изменения цвета и для определения частоты звука должна быть одинаковой).

Возможно, что-то вроде aubio, которое я нашел через этот ответ stackoverflow к поиску "обнаружение частоты" может помочь вам. В противном случае проверьте wikipedia для определение высоты тона и/или некоторые из тонны библиотек обработки сигналов там.

Ответ 5

Сначала обратитесь к проблеме с пальцем по объективу. Когда палец находится на объективе, вы не получаете статический черный кадр (как можно было бы предположить). Окружающий свет фактически проходит через ваш палец, чтобы создать красноватый кадр. Кроме того, картина кровотока в пальце приводит к небольшим периодическим изменениям в этой красной рамке (попробуйте открыть приложение для камеры, полностью положив палец на объектив). Кроме того, если окружающего света недостаточно, вы всегда можете включить вспышку/факел камеры, чтобы компенсировать это.

Для процедуры с открытым исходным кодом (и шаг за шагом) попробуйте:

http://www.ignaciomellado.es/blog/Measuring-heart-rate-with-a-smartphone-camera

я бы посоветовал вам прочитать следующий патент на измерение пульса:

http://www.google.com/patents/WO2013042070A1?cl=en

Ответ 6

Я бы:

1) Определите период от пика до пика... Если период согласован в течение определенного порогового значения времени.. Затем помечайте HB как действительный.

2) Я бы реализовал алгоритм обнаружения outliar... Любой бит, который выходит за пределы определенного нормированного порога. Будет считаться выбросом a, таким образом, я бы использовал последний обнаруженный бит вместо вычисления моего BPM.

Еще один более сложный подход - использовать фильтр Калмана или что-то вроде того, чтобы иметь возможность прогнозировать удвоение и получать более точные показания. Только после нескольких пропусков приложение почувствует, что показания недействительны и прекратите чтение.

Ответ 7

Я создал проект, который использует GPUImage фильтры, средний цвет и экспозицию, чтобы обнаружить ваш пульс. Оценка импульса основывается на текущем средстве зеленой составляющей отфильтрованного изображения.

Оптический импульсный считыватель