天天看点

一段很有意思小代码:视频中提取心率

通过功率谱的方法估计视频中人脸的心率

原理:

由麻省理工学院多媒体实验室提出的,基于光电容积脉搏波描记( Photoplethysmography,PPG)原理,结合独立成分分析,利用人面部视频测量出了心率,这种方法与被测试者是无接触的。PPG原理就是血液对光的吸收率大于周围组织,所以血容量的改变会影响血液对光的吸收程度。

1981年,Nijboer等提出PPG信号的强度会受到血管运动、血液容量和红血球的位置等因素的影响。随着对PPG信号的研究越来越多,人们在PPG信号中发现了呼吸、心率等多种频率的信号。呼吸时,静脉血液由胸部起伏产生的压力送回心脏,产生了与呼吸同步的血液灌注波动,所以PPG信号中包含与呼吸同频率的信号啊。PPG信号由于心脏的周期性波动引起外周血管内血容量周期性变化而呈现周期性,所以通过分析PPG信号可以得到心率信息

2010年美国麻省理工学院多媒体实验室通过对PPG信号的研究,开创性的提出了基于人脸视频的脉搏测量方法。他通过提取心脏跳动引起的人脸肤色的微弱变化来测量心率。这种方法采用非接触式测量,消除了传统仪器测量与患者接触而产生的不适感。但是该方法测量的是人脸的颜色的微小变化,所以对光照的改变比较敏感

根据光电容积脉搏波描记PPG原理,人的肤色会随着血液容量的变化发生变化,而血液容量的改变主要是由于心脏跳动引起的充血和放血造成的。因此从视频中提取心率,可以将人脸的彩色视频中的肤色随时间变化做为观察信号,在不同波长的光照下,血液吸收的光和反射的光会有细微的变化,表现为脉搏波PPG信号振幅的变化。

血液对波长550nm的光的吸收能力最强,其中,血液对红色光的吸收能力最弱,对绿色光的吸收能力最强,因此录制视频时的R、G、B传感器采集到的观察信号中,观察绿色光通道来识别PPG信号效果最好。在视频的每一帧取一个相同位置的ROI框,计算框内RGB绿色通道的平均值作为此帧对应时刻的采样点,在得到GREEN通道的时域信号之后,通过滤波器,之后得到滤波后的信号的功率谱,功率谱峰值对应的横坐标即为每秒的心跳数。

整个流程如下图:

一段很有意思小代码:视频中提取心率

内容:

1.读取视频

以图片的方式将视频按帧储存于文件夹figure内

2. ROI区域定位

显示第一帧图像,在第一帧图像内鼠标选点,确定ROI区域。因为人面部动脉血管主要分布在鼻翼两侧和嘴四周,所主要选取脸颊部分作为人脸检测心率的ROI区域(这里就不放脸脸的实验图了,以手腕代替-_-其实都差不多)

一段很有意思小代码:视频中提取心率
[x,y]=ginput(1);  %点击鼠标选点
x0=[x-len,y-len];
ROI = [x0(1)-len, x0(2)-len, 2*len, 2*len];
rectangle ('Position', ROI, 'EdgeColor', 'R', 'LineWidth', 2)
hold off
x0=round(x0);
Y=imcrop(image,[x0(1),x0(2),len,len]);
           

3.获得RGB曲线

通过人脸的定位及跟踪,确定ROI区域后,取ROI区域所有像素点像素值的平均值,做出ROI区域内时域的R、G、B值的曲线

一段很有意思小代码:视频中提取心率
file_path =  'E:\研一下课程\医学信号处理\实验三\提取心率\figure\';% 图像文件夹路径
file_name='original_frame';
suffix='.bmp';
img_path_list = dir([file_path,'*.bmp']);%获取该文件夹中所有jpg格式的图像
img_num = length(img_path_list);%获取图像总数量
if img_num > 0 %有满足条件的图像
        for j = 1:img_num %逐一读取图像
            order_num=num2str(j);
            total_path=strcat(file_path,file_name,order_num,suffix);
            image =  imread(total_path);
            image=double(image);
            Y=imcrop(image,[x0(1),x0(2),len,len]);
            %Y=imcrop(image,[676,333,20,20]);
            R=Y(:,:,1);
            G=Y(:,:,2);
            B=Y(:,:,3);
            r(j)=mean(mean(R));%红色均值
            g(j)=mean(mean(G));%绿色均值
            b(j)=mean(mean(B));%蓝色均值
        end
end
           

通过观察多个视频ROI区域的RGB三通道像素值的均值曲线可以看出,绿色通道(green通道)的曲线具噪声较小,但是由于光照等外部环境及人在视频录制过程中的移动产生的误差导致曲线会出现很多毛刺,影响了后续提取心率的计算。

4.滤波

设计巴特沃兹带通滤波器,周岁内婴儿心跳频率大约为:100-120 次/分,故而滤波器通带频率近似设置为1.5~2Hz(成人的话频率适当更改,1-2Hz足够了)。

fp=[1.2,2];    %通带
fst=[0.5,3];   %阻带
wp=2.*fp./fs;    %设置通带频率
ws=2.*fst./fs;   %设置阻带频率
ap=1;            %设置通带波纹系数
as=20;           %设置阻带波纹系数 
[n,wc]=buttord(wp,ws,ap,as); %巴特沃兹带通滤波器,n为滤波器阶数
[b0,a0]=butter(n,wc);
[h,w]=freqz(b0,a0);

           

5.通过带通滤波器之后,可以得到G通道信号的时域图像.再对时域信号进行FFT,计算面部信号频谱,然后计算面部信号经过信号处理之后得到的功率谱

一段很有意思小代码:视频中提取心率

用find函数读取上图数据中第一个峰值,得到相应横坐标,x*60即为心率,经过计算,就可以得到心率,我一般在88左右。

超简单

虽然跟那些专业的比差很多,但也可以拿去忽悠外行人不是

继续阅读