本文地址:https://blog.csdn.net/itnerd/article/details/109078291

实验效果

实验思路

  • 用 opencv 打开摄像头,读取指定窗口区域的RGB分量均值,本实验读取前额皮肤
  • 用 matplotlib 绘制动态序列曲线
  • 用 HP 滤波过滤RGB序列的趋势部分,保留波动信息,如第2列图所示
  • 对 HP 滤波后的残差,即波动信息,做FFT变换,获得信号频谱
  • 绿色分量频谱的尖峰反映了心跳的频率,正常人的心跳频率在 1~2 Hz 之间

代码实现

采用多线程的模式:

  • 线程一作为生产者,用于 opencv 读取图片中的RGB信号,并发送到一个公共队列 data_queue
  • 线程二作为消费者,但实际不消费,只是读取公共队列上的信息并用 matplotlib 画图
  • 当公共队列满了之后,线程一无法插入新数据,这时由线程一弹出队首的数据,即最早的信号值

线程一

class Producer(threading.Thread):def __init__(self,data_queue,*args,**kwargs):super(Producer, self).__init__(*args,**kwargs)self.data_queue = data_queuedef run(self):capture = cv2.VideoCapture(0)  # 0是代表摄像头编号,只有一个的话默认为0capture.set(cv2.CAP_PROP_FPS, 10)try:t0 = time.time()while (True):ref, frame = capture.read()frame = frame[:,::-1,:].copy()H, W, _ = frame.shapew, h = 40, 40x, y = W//2 -w//2, H//4-h//2area = frame[y:y + h, x:x + w, :]cv2.rectangle(frame, (x,y), (x+w,y+h), (0,255,0), 2)frame[:h,:w] = areat = time.time()-t0cv2.putText(frame, 't={:.3f}'.format(t), (10, H-10), cv2.FONT_HERSHEY_PLAIN, 1.2, (255, 255, 255), 2)cv2.imshow("face", frame)B = np.average(area[:,:,0])G = np.average(area[:,:,1])R = np.average(area[:,:,2])if self.data_queue.full():self.data_queue.queue.popleft()self.data_queue.put((t,B,G,R))c = cv2.waitKey(10) & 0xff  # 等待10ms显示图像,若过程中按“Esc”退出if c == 27:capture.release()breakexcept:traceback.print_exc()finally:capture.release()cv2.destroyAllWindows()if self.data_queue.full():self.data_queue.get()self.data_queue.put('Bye')print('Producer quit')

线程二

从公共队列中读取原始的 RGB 信号,做 HP 滤波,做傅里叶变换,作图

class Consumer(threading.Thread):def __init__(self,data_queue,*args,**kwargs):super(Consumer, self).__init__(*args,**kwargs)self.data_queue = data_queuedef run(self):time.sleep(1)fig, axes = plt.subplots(3, 3)axes[0, 0].set_title('原始信号')axes[0, 1].set_title('HP滤波残差')axes[0, 2].set_title('FFT频谱')axes[0, 0].set_ylabel('Blue')axes[1, 0].set_ylabel('Green')axes[2, 0].set_ylabel('Red')axes[2, 0].set_xlabel('Time(s)')axes[2, 1].set_xlabel('Time(s)')axes[2, 2].set_xlabel('Frequency(Hz)')start = Nonelines = [None, None, None]glines = [None, None, None]rlines = [None, None, None]flines = [None, None, None]BGR = [None, None, None]g = [None, None, None]r = [None, None, None]f = [None, None, None]num_fft = 256while True:# time.sleep(0.2)if self.data_queue.qsize() > 2:if self.data_queue.queue[-1] == 'Bye':breakts, BGR[0], BGR[1], BGR[2] = zip(*self.data_queue.queue)t = ts[-1] if len(ts) > 0 else 0for i in range(3):g[i] = hp(BGR[i], 1000)r[i] = BGR[i] - g[i]# FFTfor i in range(3):rr = r[i][-num_fft:]f[i] = np.fft.fft(rr, num_fft)f[i] = np.abs(f[i])[:num_fft//2]fs =len(rr)/ (ts[-1] - ts[-len(rr)])if start is None:start = 1lines[0] = axes[0,0].plot(ts, BGR[0], '-b')[0]lines[1] = axes[1,0].plot(ts, BGR[1], '-g')[0]lines[2] = axes[2,0].plot(ts, BGR[2], '-r')[0]glines[0] = axes[0,0].plot(ts, g[0], '-k')[0]glines[1] = axes[1,0].plot(ts, g[1], '-k')[0]glines[2] = axes[2,0].plot(ts, g[2], '-k')[0]rlines[0] = axes[0, 1].plot(ts, r[0], '-b')[0]rlines[1] = axes[1, 1].plot(ts, r[1], '-g')[0]rlines[2] = axes[2, 1].plot(ts, r[2], '-r')[0]flines[0] = axes[0, 2].plot(np.arange(num_fft//2)*fs/num_fft, f[0], '-b', marker='*')[0]flines[1] = axes[1, 2].plot(np.arange(num_fft//2)*fs/num_fft, f[1], '-g', marker='*')[0]flines[2] = axes[2, 2].plot(np.arange(num_fft//2)*fs/num_fft, f[2], '-r', marker='*')[0]for i in range(3):lines[i].set_xdata(ts)lines[i].set_ydata(BGR[i])glines[i].set_xdata(ts)glines[i].set_ydata(g[i])rlines[i].set_xdata(ts)rlines[i].set_ydata(r[i])flines[i].set_xdata(np.arange(num_fft//2)*fs/num_fft)flines[i].set_ydata(f[i])for i in range(3):axes[i,0].set_xlim([t - 10, t + 1])axes[i,0].set_ylim([np.min(BGR[i][-num_fft:]), np.max(BGR[i][-num_fft:])])axes[i, 1].set_xlim([t - 10, t + 1])axes[i, 1].set_ylim([np.min(r[i][-num_fft:]), np.max(r[i][-num_fft:])])axes[i, 2].set_xlim([0, fs//2])axes[i, 2].set_ylim([np.min(f[i]), np.max(f[i])])plt.pause(0.1)print('Consumer quit')

主函数

N = 300
data_queue = Queue(N)p = Producer(data_queue)
p.start()
c = Consumer(data_queue)
c.start()p.join()
c.join()
print('EXIT')

实验总结

  • 原始信号对环境光照、人体晃动非常敏感,会产生幅度较大的趋势变化,用 HP 滤波可以捕获这种整体趋势的变化,将其剔除

  • 从图中可以看出,RGB 三个分量中,绿色分量最能反映心跳信息,和文献中的结果一致

  • 求得信号的频谱之后,如何转化成心率?直接用频率乘以 60 即可

  • 完整代码下载

python 使用摄像头监测心率相关推荐

  1. Python 使用摄像头监测心率!这么强吗?

    实验效果 实验思路 用 opencv 打开摄像头,读取指定窗口区域的RGB分量均值,本实验读取前额皮肤 用 matplotlib 绘制动态序列曲线 用 HP 滤波过滤RGB序列的趋势部分,保留波动信息 ...

  2. Python 使用摄像头测试心率 webcam-pulse-detector

    一.环境 1. 首先是githab上的开源项目 本篇文章也只是搭建下环境,和遇到的一些问题,供大家参考     连接:https://github.com/thearn/webcam-pulse-de ...

  3. 心跳之旅—iOS用手机摄像头检测心率(PPG)

    本文中涉及到的要点主要有: AVCapture Core Graphics Delegate & Block RGB -> HSV 带通滤波 基音标注算法(TP-Psola) 光电容积脉 ...

  4. python实现摄像头拍照_使用Python控制摄像头拍照并发邮件

    o1 前言 为什么会有写这个程序的想法呢? 最初的想法是写一个可以用电脑前置摄像头拍照的程序,在舍友使用你电脑的时候,不经意间获取到一大堆奇葩舍友的表情包. 然后我又突发奇想,要不搞个开机启动吧,这样 ...

  5. opencv python 从摄像头获取视频、帧率、分辨率等属性设置和使用

    opencv python 从摄像头获取视频.帧率.分辨率等属性设置和使用 文章目录: 1,为了获取视频,你应该创建一个 VideoCapture 对象.他的参数可以是设备的索引号,或者是一个视频文件 ...

  6. python调用摄像头转向_教你如何利用python调用摄像头

    这篇文章主要介绍了python调用摄像头的示例代码,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下 一.打开摄像头 import cv2 import numpy as np def v ...

  7. python控制摄像头拍照_python+opencv+pyqt5控制摄像头在Qlabel上显示

    import cv2 import numpy as numpy from PIL import * import sys from PyQt5.QtWidgets import * from PyQ ...

  8. python捕获摄像头帧_Xuggler教程:帧捕获和视频创建

    python捕获摄像头帧 注意:这是我们的" Xuggler开发教程 "系列的一部分. 到目前为止,在我们的Xuggler教程系列中,我们已经对视频处理的Xuggler进行了介绍, ...

  9. 基于python的分布式扫描器_基于python的服务器监测系统的设计

    基于 python 的服务器监测系统的设计 高正 ; 徐浩 ; 余曼 [期刊名称] <电脑知识与技术> [年 ( 卷 ), 期] 2017(013)002 [摘要] 本文介绍了一种基于 P ...

最新文章

  1. 记一次网站部署遇到的问题
  2. SQL SERVER 2008过了评估期
  3. YbtOJ#832-鸽子饲养【凸包,Floyd】
  4. Hibernate学习(1):查询demo
  5. 深度学习要多深_才能读懂人话?
  6. Varnish由于cookie过大返回503
  7. 4月18日云栖精选夜读 | 阿里靠什么支撑 EB 级计算力?
  8. Timer运行多个TimeTask
  9. 【android原生态RPG游戏框架源码】
  10. Insert Delete GetRandom O(1)
  11. 百度云盘不限速下载大文件(2021-11亲测有效)
  12. winform 固定splitContainer某一部分大小
  13. MAVEN配置之SETTING配置
  14. 清理注册表 php,怎样清理注册表?
  15. 小技巧(8)pimple模式
  16. 事件抽取(event extraction)
  17. HashMap中的bucket介绍
  18. 【C++】利用Unicode控制字符-RLO构造欺骗性文件后缀
  19. ifstream 中 getline读文件三种方式
  20. WinCE EBOOT的入口Startup.s

热门文章

  1. 计算机一接上网线重新启动,一插上网线电脑会自动重启解决方法
  2. 人人憎恨的大数据杀熟你了解吗? 大数据杀熟”是否真的存在?
  3. 携程回应大数据杀熟并致歉 二次支付无票是系统Bug
  4. Unable to attach or mount volumes ... timed out waiting for the condition
  5. 2022-2028全球与中国制粒机市场现状及未来发展趋势
  6. bugkuctf never give up
  7. 错误 java.util.MissingResourceException:
  8. 【洛谷】P1067 多项式输出【模拟】
  9. http文件上传到web服务器,上传到ftp服务器
  10. 按键精灵 android 精简版,超精简的游戏脚本(适合大部分游戏)