tomar ritmo pulsometro puede presion para normal medir medidor frecuencia con cardiaco cardiaca arterial app ios iphone objective-c algorithm camera

pulsometro - Algoritmo de detección de frecuencia cardíaca iOS



ritmo cardiaco normal (7)

Hice un proyecto que usa filtros GPUImage , color promedio y exposición, para detectar tu pulso. El pulso se calcula según el promedio de ejecución del componente verde de la imagen filtrada.

Lector de pulso óptico

Estoy tratando de implementar la funcionalidad de grabación de latidos del corazón en una aplicación que estoy desarrollando.

El método preferido para hacer esto es usar la cámara del iPhone con la luz encendida, hacer que el usuario coloque su dedo sobre la lente y detectar fluctuaciones en la alimentación de video, que corresponden al corazón del usuario.

Encontré un muy buen punto de partida con la siguiente pregunta de desbordamiento de pila here

La pregunta proporciona un código útil para trazar un gráfico de tiempo de latido del corazón.

Muestra cómo iniciar una sesión AVCaptureSession y encender la luz de la cámara así:

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 en este ejemplo debe ser un <AVCaptureVideoDataOutputSampleBufferDelegate> Y, por lo tanto, tendrá que implementar el siguiente método para obtener datos de cámara sin procesar:

- (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 se convierte en HSV y es Hue el que se controla en busca de fluctuaciones.

Y RGB a HSV se implementa de la siguiente manera

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

El valor de paso bajo calculado en capureOutput: inicialmente proporciona datos erráticos, pero luego se estabiliza a lo siguiente:

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

Un ejemplo de los datos erráticos proporcionados inicialmente está aquí:

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

El valor de pase bajo se vuelve positivo cada vez que hay un latido del corazón. Así que probé un algoritmo de detección en vivo muy simple que básicamente mira el valor actual, y ve si es positivo, también mira el valor anterior, si es negativo, detecta que el negativo va a positivo y reproduce un pitido.

El problema con esto es que la información no siempre es tan perfecta como la anterior, a veces hay lecturas positivas anómalas entre las lecturas negativas y viceversa.

Un gráfico del valor de pase bajo en el tiempo se ve así:

Curiosamente, la anomalía anterior es bastante común, si grabo un gráfico durante un tiempo veré una anomalía en forma muy similar varias veces.

En mi algoritmo de detección de latido muy simple, si ocurre una anomalía como la que se muestra arriba, el número de latidos contados en el período de detección (10 segundos) puede dispararse en 4 o 5 latidos. Esto hace que el BPM calculado sea muy impreciso. Pero tan simple como es, funciona alrededor del 70% del tiempo.

Para combatir este problema probé lo siguiente.

1. Comenzó a grabar los últimos 3 valores de paso bajo en una matriz

2. Luego miró para ver si el valor medio tenía dos valores más pequeños que lo rodeaban antes y después. (Detección de picos básicos)

3.Consumió este escenario como un tiempo y lo agregó al total acumulado de tiempos en un tiempo dado.

Sin embargo, este método es tan vulnerable a las anomalías como cualquier otro. Y en realidad parecía ser un método peor. (Al reproducir pitidos en vivo después de la detección, parecían mucho más erráticos que el algoritmo de positivo a negativo)

Mi pregunta es si pueden ayudarme a encontrar un algoritmo que pueda detectar con fiabilidad cuándo se produce un latido cardíaco con una precisión razonable.

Otro problema que me doy cuenta de que voy a tener que abordar es detectar si el dedo de un usuario está o no en el objetivo.

Pensé en detectar valores erráticos de paso bajo, pero el problema es que las cuentas de filtro de paso bajo para valores erráticos las suavizan con el tiempo. Entonces, la ayuda allí sería apreciada también.

Gracias por tu tiempo.


Intentas detectar un latido del corazón "manualmente", que no será muy robusto. Diría que su mejor opción es algo así como una biblioteca de detección de tono o frecuencia (las matemáticas para detectar la frecuencia de un cambio de color y para detectar la frecuencia de un sonido deben ser idénticas).

Tal vez algo como aubio que encontré a través de this respuesta a la búsqueda de "detección de frecuencia" puede ayudarte. De lo contrario, consulte la wikipedia para la detección de tono y / o algunas de las toneladas de bibliotecas de procesamiento de señales que existen.


La respuesta a esta pregunta es un poco complicada, ya que necesita hacer varias cosas para procesar la señal y no hay una sola forma "correcta" de hacerlo. Sin embargo, para su filtro, quiere usar un filtro de paso de banda . Este tipo de filtro le permite especificar un rango de frecuencias que se aceptan tanto en el extremo alto como en el bajo. Para un latido del corazón humano, sabemos cuáles deberían ser estos límites (no menos de 40 latidos por minuto y no más de 250 latidos por minuto) para que podamos crear un filtro que elimine las frecuencias fuera de este rango. El filtro también mueve los datos a centrarse en cero, por lo que la detección de picos se vuelve mucho más fácil. Este filtro le dará una señal mucho más suave, incluso si los usuarios aumentan / disminuyen la presión de sus dedos (hasta cierto punto). Después de eso, también será necesario realizar un suavizado adicional y la eliminación de valores atípicos.

Un tipo específico de filtro de paso de banda que he usado es un filtro de mantequilla. Esto es un poco complicado para crear a mano, ya que el filtro cambia en función de la frecuencia en la que está recopilando sus datos. Afortunadamente, hay un sitio web que puede ayudar con esto here . Si está recopilando sus datos a 30 fps, entonces la frecuencia será de 30 hz.

He creado un proyecto que combina todo esto y detecta el ritmo cardíaco de un usuario lo suficientemente bien como para incluirlo en mi aplicación en la tienda de aplicaciones de iOS. He hecho que el código de detección de frecuencia cardíaca esté disponible en github .


Me gustaría :

1) Detecta el período de pico a pico ... Si el período es consistente dentro de un cierto umbral de período ... Entonces marca el HB como válido.

2) Implementaría un algoritmo de detección outliar ... Cualquier latido que vaya más allá de un cierto umbral normalizado. Sería considerado un valor atípico y, por lo tanto, utilizaría el último latido detectado para calcular mi BPM.

Otro enfoque más complejo sería usar un filtro de Kalman o algo así para poder predecir los valores por minuto y obtener lecturas más precisas. Solo después de unos pocos saltos la aplicación detectará que las lecturas no son válidas y detendrá la lectura. leyendo.


Parece que ya tienes otro método, pero una cosa que podrías intentar es usar un pequeño filtro mediano . Por ejemplo, el uso de la mediana de, por ejemplo, 3 a 7 valores de entrada para cada valor de salida suavizará esos picos sin destruir la forma general de los datos no anónimos.


Primero abordando su problema con el dedo sobre la lente. Cuando el dedo está en la lente, no obtienes un marco negro estático (como uno podría suponer). La luz ambiental realmente pasa a través de su dedo para crear un marco rojizo. Además, el patrón de flujo sanguíneo en el dedo provoca ligeras variaciones periódicas en ese marco rojo (intente abrir la aplicación de la cámara, colocando el dedo por completo en la lente). Además, si la luz ambiental no es suficiente, siempre puede encender el flash / flash de la cámara para compensar eso.

Para un procedimiento de código abierto (y paso a paso), intente:

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

también, le aconsejo que lea la siguiente patente sobre medición de pulso:

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


Supongo que estás usando tu propio dedo. ¿Estás seguro de que no tienes latidos cardíacos irregulares? Además, querrás manejar a personas con latidos cardíacos irregulares. En otras palabras, debe probar con una amplia variedad de valores de entrada. Definitivamente pruébalo con tus padres u otros familiares mayores, ya que es más probable que tengan problemas cardíacos. Aparte de eso, su problema básico es que su fuente de entrada va a ser ruidosa; básicamente estás tratando de recuperar la señal de ese ruido. A veces eso será imposible, y tendrá que decidir si desea generar ruido en su informe o simplemente ignorar el flujo de datos cuando es demasiado ruidoso.

Sigue intentando diferentes valores de filtro ; tal vez necesites un filtro de paso aún más bajo. De los comentarios, parece que su filtro de paso bajo no era bueno; hay toneladas de recursos para filtrar en la web. Si tienes buenas herramientas de visualización, esa será la mejor manera de probar tu algoritmo.

Puede intentar reducir los datos , lo que lo suavizará. También puede descartar muestras que se encuentren fuera de un rango válido, ya sea descartando el valor por completo, reemplazándolo con el promedio de la muestra anterior y siguiente, y / o ajustándolo a un máximo predeterminado o calculado.

Mi mayor problema con este tipo de aplicaciones es que los problemas se tratan como datos reales y en vivo. Una de las bicicletas en mi gimnasio da lecturas de bpm inútiles porque, de vez en cuando, no puede encontrar mi pulso y de repente piensa que mi corazón va a 300 bpm. (Lo cual no es así, se lo pregunté a mi médico). Para una sesión de 20 minutos, el promedio que tiene es inútil. Creo que es más útil ver el promedio de (por ejemplo) los últimos diez tiempos normales más la tasa de anomalías en lugar de "Intenté meter los últimos 20 segundos en este algoritmo y aquí está la basura que escupió". Si puede crear un filtro separado que indique anomalías, creo que tendrá una aplicación mucho más útil.