[Python, Алгоритмы, Лайфхаки для гиков, Научно-популярное, Программирование] Определяем пульс по вебкамере в 50 строчек кода
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет Хабр.Однажды мне попалось описание приложения для Android, которое определяло пульс по камере телефона, просто по общей картинке. Интересный момент был в том, что ревьюеры не поверили в возможность такого определения пульса, и приложение было отклонено. Чем дело кончилось у автора программы, не знаю, но стало интересно проверить, возможно ли это.Для тех кому интересно что получилось, продолжение под катом.Разумеется, я не буду делать приложение под Android, гораздо проще проверить идею на языке Python.Получаем данные с камерыСначала мы должны получить поток с вебкамеры, для чего воспользуемся OpenCV. Код является кроссплатформенным, и может работать как под Windows, так и под 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()
Идея определения пульса состоит в том, что оттенок кожи слабо меняется из-за протекания крови в сосудах, поэтому нам понадобится кроп картинки, на котором будет только фрагмент кожи.
x, y, w, h = 800, 500, 100, 100
crop_img = img[y:y + h, x:x + w]
cv2.imshow('Crop', crop_img)
Если все было сделано правильно, при запуске программы мы должны получить примерно такую картинку с камеры (заблюрено из соображений приватности) и кропа:
ОбработкаПосле того, как у нас есть поток с камеры, все довольно просто. Для выбранного фрагмента мы получаем усредненное значение цвета и добавляем его в массив вместе со временем измерения.
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.Собственно и все. Запускаем программу, подбираем такое положение, чтобы в кропе с камеры был только фрагмент кожи, принимаем "позу мыслителя", подперев голову рукой - изображение должно быть максимально неподвижно. И вуаля - это действительно работает!
Возможно, из заголовка не совсем очевидно, но камера не прикладывается к коже, мы просто анализируем общую картинку с человеком на экране. И удивительно, что даже на таком расстоянии изменение оттенка кожи вполне уверенно фиксируется камерой! Разумеется, по клеточкам считать не точно, примерный пульс получился около 75bpm. Для сравнения, результат с поверенного китайскими мастерами пульсоксиметра:
ЗаключениеКак ни странно, но это действительно работает. Если честно, в результате я был не уверен. Разумеется, для реального использования нужно сначала найти лицо на изображении, но встроенная функция поиска лиц в OpenCV также есть. И конечно, нужна несложная математика для выделения периода из достаточно шумных данных.Для желающих поэкспериментировать самостоятельно, исходный код целиком под спойлером.Spoiler
import numpy as np
from matplotlib import pyplot as plt
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, 1280)
cap.set(cv2.CAP_PROP_FPS, 30)
# 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()
И как обычно, всем удачных экспериментов
===========
Источник:
habr.com
===========
Похожие новости:
- [Машинное обучение] Частотный анализ русского текста и облако слов на Python
- [.NET, ASP, C#, Программирование, Тестирование IT-систем] Я десять лет страдал от ужасных архитектур в C# приложениях — и вот нашел, как их исправить
- [Будущее здесь, Гаджеты, Криптография, Лайфхаки для гиков] Рутокен ЭЦП 2.0 3000, COVID-19, УЦ Росреестра и операции с Росреестом онлайн ver. 2.0
- [JavaScript, Программирование, Разработка веб-сайтов] JavaScript: область видимости простыми словами (перевод)
- [Python, Программирование, Машинное обучение] Как мы научили робота чувству юмора
- [IT-компании, Мозг, Научно-популярное, Учебный процесс в IT] Большая роль «маленького разговора»
- [Программирование, Анализ и проектирование систем, Управление разработкой] Как программист читает «Происхождение видов» Дарвина
- [Машинное обучение, Научно-популярное, Социальные сети и сообщества] Анализ тональности в русскоязычных текстах, часть 2: основные исследования
- [Математика, Научно-популярное] Компьютерный поиск помог разобраться с 90-летней математической задачей (перевод)
- [Data Mining, Natural Language Processing, Python, Изучение языков, Машинное обучение] Делаем параллельный корпус из книг с помощью sentence embeddings
Теги для поиска: #_python, #_algoritmy (Алгоритмы), #_lajfhaki_dlja_gikov (Лайфхаки для гиков), #_nauchnopopuljarnoe (Научно-популярное), #_programmirovanie (Программирование), #_python, #_pulsometr (пульсометр), #_python, #_algoritmy (
Алгоритмы
), #_lajfhaki_dlja_gikov (
Лайфхаки для гиков
), #_nauchnopopuljarnoe (
Научно-популярное
), #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:09
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет Хабр.Однажды мне попалось описание приложения для Android, которое определяло пульс по камере телефона, просто по общей картинке. Интересный момент был в том, что ревьюеры не поверили в возможность такого определения пульса, и приложение было отклонено. Чем дело кончилось у автора программы, не знаю, но стало интересно проверить, возможно ли это.Для тех кому интересно что получилось, продолжение под катом.Разумеется, я не буду делать приложение под Android, гораздо проще проверить идею на языке Python.Получаем данные с камерыСначала мы должны получить поток с вебкамеры, для чего воспользуемся OpenCV. Код является кроссплатформенным, и может работать как под Windows, так и под 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() x, y, w, h = 800, 500, 100, 100
crop_img = img[y:y + h, x:x + w] cv2.imshow('Crop', crop_img) ОбработкаПосле того, как у нас есть поток с камеры, все довольно просто. Для выбранного фрагмента мы получаем усредненное значение цвета и добавляем его в массив вместе со временем измерения. 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()] 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) Возможно, из заголовка не совсем очевидно, но камера не прикладывается к коже, мы просто анализируем общую картинку с человеком на экране. И удивительно, что даже на таком расстоянии изменение оттенка кожи вполне уверенно фиксируется камерой! Разумеется, по клеточкам считать не точно, примерный пульс получился около 75bpm. Для сравнения, результат с поверенного китайскими мастерами пульсоксиметра: ЗаключениеКак ни странно, но это действительно работает. Если честно, в результате я был не уверен. Разумеется, для реального использования нужно сначала найти лицо на изображении, но встроенная функция поиска лиц в OpenCV также есть. И конечно, нужна несложная математика для выделения периода из достаточно шумных данных.Для желающих поэкспериментировать самостоятельно, исходный код целиком под спойлером.Spoiler import numpy as np
from matplotlib import pyplot as plt 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, 1280) cap.set(cv2.CAP_PROP_FPS, 30) # 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() =========== Источник: habr.com =========== Похожие новости:
Алгоритмы ), #_lajfhaki_dlja_gikov ( Лайфхаки для гиков ), #_nauchnopopuljarnoe ( Научно-популярное ), #_programmirovanie ( Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:09
Часовой пояс: UTC + 5