Salut, Habr.
Une fois, je suis tombé sur une description d'une application Android qui déterminait la fréquence cardiaque par la caméra du téléphone, juste par l'image générale. La caméra n'a pas été appliquée au doigt, elle n'était pas éclairée par la LED. Un point intéressant était que les examinateurs ne croyaient pas à la possibilité d'une telle détermination du pouls et la demande a été rejetée. Je ne sais pas comment l’auteur du programme est arrivé, mais il est devenu intéressant de vérifier si cela était possible.
Pour ceux qui s'intéressent à ce qui s'est passé, la suite sous la coupe.
Bien sûr, je ne ferai pas d'application pour Android, il est beaucoup plus facile de tester l'idée en Python.
Nous recevons des données de la caméra
Tout d'abord, nous devons obtenir un flux de la webcam, pour lequel nous utiliserons OpenCV. Le code est multiplateforme et peut fonctionner à la fois sous Windows et Linux / OSX.
import cv2
import io
import time
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
while(True):
ret, frame = cap.read()
# Our operations on the frame come here
img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the frame
cv2.imshow('Crop', crop_img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
L'idée de déterminer le pouls est que le teint de la peau change légèrement en raison du flux sanguin dans les vaisseaux, nous avons donc besoin d'un recadrage de l'image, qui ne contiendra qu'un fragment de la peau.
x, y, w, h = 800, 500, 100, 100
crop_img = img[y:y + h, x:x + w]
cv2.imshow('Crop', crop_img)
Si tout a été fait correctement, lors du démarrage du programme, nous devrions obtenir quelque chose comme ça de la caméra (floue pour des raisons de confidentialité) et recadrer:
Traitement
, , . .
heartbeat_count = 128
heartbeat_values = [0]*heartbeat_count
heartbeat_times = [time.time()]*heartbeat_count
while True:
...
# Update the list
heartbeat_values = heartbeat_values[1:] + [np.average(crop_img)]
heartbeat_times = heartbeat_times[1:] + [time.time()]
numpy.average , , .
:
fig = plt.figure()
ax = fig.add_subplot(111)
while(True):
...
ax.plot(heartbeat_times, heartbeat_values)
fig.canvas.draw()
plot_img_np = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
plot_img_np = plot_img_np.reshape(fig.canvas.get_width_height()[::-1] + (3,))
plt.cla()
cv2.imshow('Graph', plot_img_np)
: OpenCV numpy, matplotlib , numpy.fromstring.
.
, , , " ", - . - !
, , , . , ! , 0.5% , " ", . , , 75bpm. , :
, .. , , .
, . , . , , OpenCV . , .
, - , ? , . cap = cv2.VideoCapture(0) cap = cv2.VideoCapture("video.mp4"), .
, .
Spoiler
import numpy as np
from matplotlib import pyplot as plt
import cv2
import io
import time
# Camera stream
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1280)
cap.set(cv2.CAP_PROP_FPS, 30)
# Video stream (optional)
# cap = cv2.VideoCapture("videoplayback.mp4")
# Image crop
x, y, w, h = 800, 500, 100, 100
heartbeat_count = 128
heartbeat_values = [0]*heartbeat_count
heartbeat_times = [time.time()]*heartbeat_count
# Matplotlib graph surface
fig = plt.figure()
ax = fig.add_subplot(111)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
crop_img = img[y:y + h, x:x + w]
# Update the data
heartbeat_values = heartbeat_values[1:] + [np.average(crop_img)]
heartbeat_times = heartbeat_times[1:] + [time.time()]
# Draw matplotlib graph to numpy array
ax.plot(heartbeat_times, heartbeat_values)
fig.canvas.draw()
plot_img_np = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
plot_img_np = plot_img_np.reshape(fig.canvas.get_width_height()[::-1] + (3,))
plt.cla()
# Display the frames
cv2.imshow('Crop', crop_img)
cv2.imshow('Graph', plot_img_np)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Et comme d'habitude, toutes les expériences réussies