从简单视频获取心率:内部代码

时间:2014-06-12 17:18:38

标签: ios matlab camera signal-processing video-processing

我试图通过我的皮肤视频找到心率。为了做到这一点,我从我的视频帧中取出一个裁剪的像素矩形,并对所有这些像素中的红色(或绿色)分量求平均值(当然,看看这个平均值如何在帧到帧之间变化)。

我对矢量进行快速傅里叶变换(每帧的平均颜色值裁剪部分)以查看哪些频率最突出。我希望看到静息的人类心率,~1Hz,非常突出。

作为测试,我拍摄了一个只有墙壁的视频,或其他应该没有周期性颜色变化的物体。我使用了三脚架和三种不同品牌的不同相机。它们中的每一个具有相似但不相同的背景频率峰值,特别是在1Hz,2Hz,5Hz和10Hz。我在自然光和荧光下拍摄,但它仍然存在。

我的最终目标是通过这种分析来区分来自非血管化皮肤的活皮肤。因此,理解为什么我为无生命物体获得这些频率峰值是VITAL。

您是否可以在自己的视频中运行此代码,并帮助解释我是否只是一个白痴?

相机拍摄:

Kodak Playsport

1920×1080 30fps(60i) 导入为mp4

佳能Vixia HF200 1440×1080 30fps(60i) 12mbps比特率 导入为.mts,我重新编码为mp4

代码基于:

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

clear all
close all
clc

%% pick data file name to be analyzed, set directory it is found in
dataDir = './data';
vidname = ['Filename.MP4'];

%% define path to file and pull out video
inFile = fullfile(dataDir,vidname);
video = VideoReader(inFile);

%% make 1D array with length equal to number of frames (time)

brightness = zeros(1, video.NumberOfFrames);
video_framerate = round( video.FrameRate); % note some places in the code must use integer value for framerate, others we directly use the unrounded frame rate

%% set region of interest for what you want to get average brightness of
frame = read(video, 1);
imshow(frame)
rect = getrect;
close all

xmin_pt = round(rect(1));
ymin_pt = round(rect(2)); 
section_width = round(rect(3)); 
section_height = round(rect(4));

%% select component of video (red green or blue)
component_selection = 1; % pick red , green, or blue

%% make 1D array of ROI averages
 for i = 1:video.NumberOfFrames,
     frame = read(video, i);
     section_of_interest = frame(ymin_pt:ymin_pt+section_height,xmin_pt:xmin_pt+section_width,:);
     colorPlane = section_of_interest(:, :, component_selection);
     brightness(i) = sum(sum(colorPlane)) / (size(frame, 1) * size(frame, 2));
 end


%% Filter out non-physiological frequencies
BPM_L = 40;    % Heart rate lower limit [bpm]
BPM_H = 600;   % Heart rate higher limit [bpm] This is currently set high to investigate the signal

% Butterworth frequencies must be in [0, 1], where 1 corresponds to half the sampling rate
[b, a] = butter(2, [((BPM_L / 60) / video_framerate * 2), ((BPM_H / 60) / video_framerate * 2)]);
filtBrightness = filter(b, a, brightness);


%% Trim the video to exlude the time where the camera is stabilizing
FILTER_STABILIZATION_TIME = 3;    % [seconds]
filtBrightness = filtBrightness((video_framerate * FILTER_STABILIZATION_TIME + 1):size(filtBrightness, 2));

%% Do FFT on filtered/trimmed signal
fftMagnitude = abs(fft(filtBrightness));

%% Plot results

figure(1)
subplot(3,1,1)
plot([1:length(brightness)]/video.FrameRate,brightness)
xlabel('Time (seconds)')
ylabel('Color intensity')
title('original signal')

subplot(3,1,2)
plot([1:length(filtBrightness)]/video.FrameRate,filtBrightness)
xlabel('Time (seconds)')
ylabel('Color intensity')
title('after butterworth filter and trim')


freq_dimension = ((1:round(length(filtBrightness)))-1)*(video_framerate/length(filtBrightness));

subplot(3,1,3)
plot(freq_dimension,fftMagnitude)
axis([0,15,-inf,inf])
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
title('Fft of filtered signal')

1 个答案:

答案 0 :(得分:1)

您的目的是通过我的皮肤视频找到心率"并且" ...通过这种分析来区分来自非血管化皮肤的活皮肤"但是你的方法是"拍摄视频...裁剪......平均红色(或绿色)组件......看看它是如何变化的"。

我认为这个前提存在问题。平均值意味着多数信号占主导地位。人类视觉是视觉数据的一个(惊人的)处理器,通常需要几十年的努力才能使机器进入甚至他们所做的一小部分。如果你无法用眼睛看着周围90%的人,并测量他们的心率,那么采用平均方法可能不是可行的方法。

您可以使用无数的统计数据来查看分布如何随时间变化,而平均值只是其中之一。如果你只看你的意思,你可能会错过这些信息。

我将如何做到这一点:

  1. 我会按照帧到帧的差异进行操作。
  2. 大多数视频编解码器具有非均匀的时间间隔。我会得到这些值,以便我可以跟踪实际(未假设)时间的变化。您当前(可能是错误的)信号可能来自CODEC以及硬件。
  3. 我会制作一部电影,使得每个新帧都是它与前一帧之间的差异。我会看20次,看看我的(惊人的)人类视觉处理系统是否可以看到任何与心跳相关或明显不相关的东西。
  4. 对于" NOT"将它们从加工,掩模,过滤器等中移除。 对于相关的,找到使它们成为感兴趣区域的方法 删除其他所有内容,截断像素强度直方图,或 其他图像增强(模糊,锐化,重新着色,边缘,旋转等) 最大的信号沿着更新的像素轴,然后处理..)
  5. 在人类视觉设备能够获得良好信号之后,我会努力使数学/计算机获得信号,并清楚地知道人类设备是优越的。

    如果我跟踪随时间推移的点/特征,我会看一下亚像素计量方法。我十年前做了一些这样的事情(thesis),虽然我认为内容可能是相关的,但在复制和运行代码之前,它也可能有所不同,值得第一次阅读。

    祝你好运。