algorytm wykrywania tętna iOS

[7]}próbuję zaimplementować funkcję nagrywania bicia serca w rozwijanej aplikacji.

[7]}preferowaną metodą jest używanie aparatu iPhone ' a z włączonym światłem, umieszczanie palca na obiektywie i wykrywanie fluktuacji w strumieniu wideo, które odpowiadają sercu użytkownika.

Znalazłem bardzo dobry punkt wyjścia z następującym pytaniem o przepełnienie stosu tutaj

Pytanie dostarcza użytecznego kodu do wykreowania bicia serca Wykres czasu.

Pokazuje, jak uruchomić Avcapturession i włączyć światło kamery w ten sposób:

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];

Self w tym przykładzie musi być <AVCaptureVideoDataOutputSampleBufferDelegate> I dlatego będzie musiał wdrożyć następującą metodę, aby uzyskać surowe dane z kamery:

- (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 jest konwertowany na HSV i to odcień jest monitorowany pod kątem fluktuacji.

I RGB do HSV jest zaimplementowane w następujący sposób

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;
}

Wartość low pass obliczona w capureOutput: początkowo dostarcza danych nieregularnych, ale potem

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

Przykład błędnych danych podanych na początku jest tutaj:

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

Wartość low pass jest dodatnia, gdy jest bicie serca. Wypróbowałem więc bardzo prosty algorytm wykrywania NA ŻYWO, który w zasadzie patrzy na aktualną wartość i widzi, czy jest dodatnia, patrzy również na poprzednią wartość, jeśli ujemna wykrywa ujemną przechodzącą na dodatnią i odtwarza dźwięk dźwiękowy.

Problem w tym, że dane nie zawsze są tak doskonałe, jak powyżej, czasami są anomalne pozytywne odczyty wśród negatywnych odczytów i vice versa.

Wykres wartości niskiego przejścia w czasie wygląda następująco: Tutaj wpisz opis obrazka

Co ciekawe powyższa anomalia jest dość powszechna, jeśli nagram Wykres przez chwilę, zobaczę bardzo podobną anomalię w kształcie wiele razy.

W moim bardzo prostym algorytmie wykrywania uderzeń, jeśli wystąpi anomalia, jak pokazano powyżej, zliczona liczba uderzeń w okresie wykrywania (10 sekund) może wzrosnąć o 4 lub 5 bity. To sprawia, że obliczony BPM jest bardzo niedokładny. Ale tak proste, jak to jest, działa około 70% czasu.

Aby zwalczyć ten problem, próbowałem następujących.

1.Rozpoczęte nagrywanie ostatnich 3 wartości dolnoprzepustowych w tablicy

2.Następnie spojrzał, czy Średnia wartość miała dwie mniejsze wartości otaczające go przed i po. (Podstawowe wykrywanie piku)

3.Policzył ten scenariusz jako beat i dodał go do sumy uderzeń w danym czas.

Ta metoda jest jednak tak samo podatna na anomalie, jak każda inna. I wydawało się, że to gorsza metoda. (Podczas odtwarzania sygnałów dźwiękowych na żywo po wykryciu wydawały się znacznie bardziej nieregularne niż algorytm dodatni do ujemnego) {]}

Moje pytanie brzmi, czy możesz mi pomóc wymyślić algorytm, który może niezawodnie wykryć, gdy wystąpi bicie serca z rozsądną dokładnością.

Innym problemem, który zdaję sobie sprawę, że będę musiał rozwiązać, jest wykrywanie, czy palec użytkownika jest na obiektywie.

Myślałem o wykryciu nieobliczalnych wartości dolnoprzepustowych, ale problem polega na tym, że filtr dolnoprzepustowy odpowiada za nieobliczalne wartości i wygładza je w czasie. Więc pomoc tam też będzie mile widziana.

Dziękuję za poświęcony czas.
Author: Community, 2013-11-04

7 answers

Odpowiedź na to pytanie jest trochę zaangażowana, ponieważ trzeba zrobić kilka rzeczy, aby przetworzyć sygnał i nie ma jednego "właściwego" sposobu, aby to zrobić. Jednak do filtra należy użyć filtra pasmowo-przepustowego . Ten typ filtra pozwala określić zakres częstotliwości, które są akceptowane zarówno na wysokich, jak i niskich końcach. Dla ludzkiego serca wiemy, jakie powinny być te granice (nie mniej niż 40 uderzeń na minutę i nie więcej niż 250 uderzeń na minutę), dzięki czemu możemy stworzyć filtr, który usuwa częstotliwości spoza tego zakresu. Filtr przesuwa również dane, aby były wyśrodkowane na zero, dzięki czemu wykrywanie szczytowe staje się znacznie łatwiejsze. Filtr ten daje znacznie bardziej płynny sygnał, nawet jeśli użytkownicy zwiększają / zmniejszają nacisk na palce (do pewnego stopnia). Następnie konieczne będzie również dodatkowe wygładzanie i usuwanie odstających.

Specyficznym typem filtra pasmowo-przepustowego, którego używałem, jest filtr Butterwortha. Jest to trochę zaangażowane do tworzenia ręcznie, ponieważ filtr zmiany w zależności od częstotliwości zbierania danych. Na szczęście istnieje strona internetowa, która może w tym pomóc tutaj. Jeśli zbierasz dane przy 30 fps, częstotliwość wyniesie 30 hz.

Stworzyłem projekt, który owija to wszystko razem i wykrywa tętno użytkownika na tyle dobrze, aby umieścić go w mojej aplikacji w sklepie z aplikacjami na iOS. Udostępniłem kod wykrywania tętna na github.

 4
Author: lehn0058,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-19 11:51:27

Zakładam, że używasz własnego palca. Na pewno nie masz nieregularnego bicia serca? Poza tym będziesz chciała obsługiwać ludzi z nieregularnym biciem serca. Innymi słowy, powinieneś testować z szeroką gamą wartości wejściowych. Zdecydowanie wypróbuj go na swoich rodzicach lub innych starszych krewnych, ponieważ mogą być bardziej narażeni na problemy z sercem. Poza tym podstawowym problemem jest to, że źródło wejściowe będzie hałaśliwe; w zasadzie próbujesz odzyskać sygnał od tego hałasu. Czasami Będzie to niemożliwe i będziesz musiał zdecydować, czy chcesz piec hałas w raporcie, czy po prostu zignorować strumień danych, gdy jest zbyt głośny.

Próbuj dalej różnych wartości filtrów ; Być może potrzebujesz jeszcze filtra dolnoprzepustowego. Z komentarzy wynika, że twój filtr dolnoprzepustowy nie był dobry; w sieci jest mnóstwo zasobów na temat filtrowania. Jeśli masz dobre narzędzia wizualizacyjne, które będą najlepszym sposobem na przetestowanie twojego algorytm.

Możesz spróbować w dół-próbkowanie danych , które wygładzi to. Możesz również odrzucić próbki , które znajdują się poza prawidłowym zakresem, albo przez całkowite odrzucenie wartości, zastąpienie jej średnią z poprzedniej i następnej próbki i/lub przez zaciśnięcie jej DO OKREŚLONEGO z góry lub obliczonego maksimum.

Mój największy problem z tego typu aplikacjami polega na tym, że czkawki są traktowane jako prawdziwe, żywe dane. Jeden z rowerów na mojej siłowni daje bezużyteczne odczyty bpm ponieważ, co jakiś czas, nie może znaleźć mojego pulsu i nagle myśli, że moje serce idzie na 300 bpm. (Co nie jest; zapytałem mojego lekarza.) Na 20-minutową sesję średnia, jaką ma, jest bezużyteczna. Myślę, że bardziej przydatne jest zobaczyć średnią (np.) ostatnich dziesięciu normalnych uderzeń plus częstotliwość anomalii, a nie "próbowałem wcisnąć ostatnie 20 sekund w ten algorytm i oto śmieci, które wypluł". Jeśli można utworzyć oddzielny filtr, który wskazuje anomalie, myślę, że będziesz miał znacznie bardziej przydatną aplikację.

 1
Author: AndrewS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-13 18:51:01

Ja bym:

1) wykrywanie okresu od szczytu do szczytu... Jeżeli okres jest spójny w określonym przedziale czasowym.. Następnie oznacz HB jako ważne.

2) zaimplementowałbym algorytm detekcji zewnętrznej... Każdy rytm, który wykracza poza pewien znormalizowany próg.. Byłby uważany za odstający, więc użyłbym ostatniego wykrytego rytmu zamiast obliczyć mój BPM.

Innym bardziej złożonym podejściem byłoby użycie filtra Kalmana lub czegoś w rodzaju, aby móc przewiduj bpm i uzyskaj dokładniejsze odczyty.. Dopiero po kilku pominięciach aplikacja wyczuje, że odczyty nie są prawidłowe i zatrzyma odczyt.

 1
Author: Kiko Lobo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-22 20:49:43

Wygląda na to, że masz już inną metodę, ale jedną rzeczą, którą możesz spróbować, jest użycie małego mediana filtra . Na przykład, użycie mediany, powiedzmy, 3 do 7 wartości wejściowych dla każdej wartości wyjściowej wygładzi te piki bez niszczenia ogólnego kształtu danych nieomylnych.

 0
Author: user1118321,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-05 17:21:02

Próbujesz wykryć pojedyncze bicie serca "ręcznie", To nie będzie zbyt mocne. Powiedziałbym, że najlepszym rozwiązaniem jest coś w rodzaju biblioteki wykrywania wysokości lub częstotliwości (matematyka wykrywania częstotliwości zmiany koloru i wykrywania częstotliwości dźwięku musi być identyczna).

Być może coś w rodzaju aubio, które znalazłem poprzez ta odpowiedź stackoverflow do wyszukiwania "Detekcja częstotliwości" może Ci pomóc. W przeciwnym razie sprawdź w Wikipedii pitch Detekcja i / lub niektóre z ton bibliotek przetwarzania sygnałów.

 0
Author: HBu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:19

Najpierw rozwiązywanie problemu z palcem na obiektywie. Gdy palec jest na obiektywie, nie masz statycznej czarnej ramki (jak można by przypuszczać). Światło otoczenia faktycznie przechodzi przez palec, aby utworzyć czerwonawą ramkę. Ponadto, wzór przepływu krwi w palcu powoduje niewielkie okresowe zmiany w tej czerwonej ramce (spróbuj otworzyć aplikację aparatu, umieszczając palec całkowicie na obiektywie). Ponadto, jeśli światło otoczenia nie wystarczy, zawsze możesz włączyć lampę błyskową/latarkę do zrekompensuj to.

W przypadku procedury open source (i krok po kroku) spróbuj:

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

Radzę również przeczytać następujący patent na pomiar pulsu:

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

 0
Author: Ameer Sheikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-19 10:05:57

Zrobiłem projekt, który używa GPUImage filtrów, średniego koloru i ekspozycji, aby wykryć Twój puls. Impuls jest szacowany na podstawie średniej bieżącej Zielonego składnika filtrowanego obrazu.

Optyczny Czytnik Impulsów

 0
Author: Vijay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-01 14:21:16