使用网络摄像头检测心跳?

6
我正在尝试创建一个应用程序,可以使用计算机网络摄像头检测心跳。我已经在编写代码两周了,开发了以下代码:
1. 使用opencv检测脸部 2. 获取额头图像 3. 应用滤镜将其转换为灰度图像[您可以跳过此步骤] 4. 每帧查找绿色像素的平均强度 5. 将平均值保存到数组中 6. 应用FFT(我使用了minim库)从FFT频谱中提取心跳(在这里,我需要一些帮助)
在这里,我需要帮助从FFT频谱中提取心跳。有人能帮我吗?这里是使用Python开发的类似应用程序,但我无法理解这段代码,所以我正在处理相同的问题。有人能帮我理解这个Python代码的部分,它正在提取心跳吗?
//---------import required ilbrary -----------
import gab.opencv.*;
import processing.video.*;
import java.awt.*;
import java.util.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
//----------create objects---------------------------------
Capture video; // camera object
OpenCV opencv; // opencv object
Minim       minim;
FFT         fft;
//IIRFilter filt;
//--------- Create ArrayList--------------------------------
ArrayList<Float> poop = new ArrayList(); 
float[] sample;
int bufferSize = 128;
int sampleRate = 512;
int bandWidth = 20;
int centerFreq = 80;
//---------------------------------------------------
void setup() {
  size(640, 480); // size of the window
  minim = new Minim(this);
  fft = new FFT( bufferSize, sampleRate);
  video = new Capture(this, 640/2, 480/2); // initializing video object
  opencv = new OpenCV(this, 640/2, 480/2); // initializing opencv object
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);  // loading haar cscade file for face detection
  video.start(); // start video
}

void draw() {
  background(0);
  // image(video, 0, 0 ); // show video in the background
  opencv.loadImage(video);
  Rectangle[] faces = opencv.detect();
  video.loadPixels();
  //------------ Finding faces in the video ----------- 
  float gavg = 0;
  for (int i = 0; i < faces.length; i++) {
    noFill();
    stroke(#FFB700); // yellow rectangle
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height); // creating rectangle around the face (YELLOW)
    stroke(#0070FF); //blue rectangle
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height-2*faces[i].height/3); // creating a blue rectangle around the forehead
    //-------------------- storing forehead white rectangle part into an image -------------------
    stroke(0, 255, 255);
    rect(faces[i].x+faces[i].width/2-15, faces[i].y+15, 30, 15);
    PImage img = video.get(faces[i].x+faces[i].width/2-15, faces[i].y+15, 30, 15); // storing the forehead aera into a image
    img.loadPixels();
    img.filter(GRAY); // converting capture image rgb to gray
    img.updatePixels();

    int numPixels = img.width*img.height;
    for (int px = 0; px < numPixels; px++) { // For each pixel in the video frame...
      final color c = img.pixels[px];
      final color luminG = c>>010 & 0xFF;
      final float luminRangeG = luminG/255.0;
      gavg = gavg + luminRangeG;
    }

    //--------------------------------------------------------
    gavg = gavg/numPixels;
    if (poop.size()< bufferSize) {
      poop.add(gavg);
    }
    else poop.remove(0);
  }
  sample = new float[poop.size()];
  for (int i=0;i<poop.size();i++) {
    Float f = (float) poop.get(i);
    sample[i] = f;
  }

  if (sample.length>=bufferSize) {
    //fft.window(FFT.NONE); 
    fft.forward(sample, 0);
    //    bpf = new BandPass(centerFreq, bandwidth, sampleRate);
    //    in.addEffect(bpf);
    float bw = fft.getBandWidth(); // returns the width of each frequency band in the spectrum (in Hz).
    println(bw); // returns 21.5332031 Hz for spectrum [0] & [512]

    for (int i = 0; i < fft.specSize(); i++)
    {
      // println( " Freq" + max(sample));
      stroke(0, 255, 0);
      float x = map(i, 0, fft.specSize(), 0, width);
      line( x, height, x, height - fft.getBand(i)*100);
     // text("FFT FREQ " + fft.getFreq(i), width/2-100, 10*(i+1));
     // text("FFT BAND " + fft.getBand(i), width/2+100, 10*(i+1));
    }
  }
  else {
    println(sample.length + " " + poop.size());
  }
}

void captureEvent(Capture c) {
  c.read();
}

那个人的脉搏太高了,就算只是坐着也是如此。 - GPPK
取决于他看的裸露/下流女孩有多暴露… - Spektre
2个回答

3

FFT被应用于128个样本的窗口中。

int bufferSize = 128;

在绘制方法期间,样本被存储在一个数组中,直到填充用于应用FFT的缓冲区。然后,在此之后保持缓冲区充满状态。要插入新样本,最旧的样本将被删除。gavg是平均灰色通道颜色。
gavg = gavg/numPixels;
if (poop.size()< bufferSize) {
  poop.add(gavg);
}
else poop.remove(0);

将粪便样本采集
sample = new float[poop.size()];
for (int i=0;i < poop.size();i++) {
    Float f = (float) poop.get(i);
    sample[i] = f;
}

现在可以将FFT应用于样本数组

fft.forward(sample, 0);

代码中只显示频谱结果。心跳频率必须计算。对于FFT中的每个带宽,您必须找到最大值,并且该位置就是心跳的频率。

for(int i = 0; i < fft.specSize(); i++)
{ // draw the line for frequency band i, scaling it up a bit so we can see it
    heartBeatFrequency = max(heartBeatFrequency,fft.getBand(i));
}

然后获取带宽以了解频率。
float bw = fft.getBandWidth();

调整频率。
heartBeatFrequency = fft.getBandWidth() * heartBeatFrequency ;

1
嗨David,感谢您的友善回复并详细说明我的代码。我已经添加了您在帖子末尾提到的建议代码段。当我运行代码时,它给出了“无穷大”的结果,请问这是为什么?再次感谢 :) - B L Λ C K
1
你解决了吗? fft.getBandWidth(),heartBeatFrequency其中一个具有无限值。验证心跳频率是否初始化为负无穷大,并且fft.getBandWidth()返回一个有效值,而不是无穷大。 - David Clifte

0

当您获取大小为128的样本(即bufferSize值)或大于该值时,请使用样本数组转发fft,然后获取频谱的峰值,这将是我们的心率。 以下论文阐述了相同的内容:

  1. 从视频中测量心率-Isabel Bush-Stanford-link(图2下方第4段解释了此内容。)
  2. 使用网络摄像头从面部RGB颜色视频进行实时心率监测-H. Rahman、M.U. Ahmed、S. Begum、P. Funk-link(第4页)

看了你的问题后,我想亲自动手试试,于是我尝试为此创建了一个代码库

不过,目前还有一些问题,希望有人能够帮忙看看。

感谢David Clifte提供这个答案,对我很有帮助。


1
自我推广仅仅是链接到你自己的库或教程并不是一个好答案。链接到它,解释为什么它解决了问题,提供如何这样做的代码,并声明你编写了它,这将成为更好的答案。参见:什么是“好”的自我推广? - 4b0
@Shree非常感谢你为我在StackOverFlow上回答问题提供了正确的指导方针。由于我刚开始贡献,我会尽力遵守任何指南,以免违反规定。我的意图并不是为了推广我的代码库、资源或教程。我只是想通知一些能够帮助他人更好地理解同一件事情的东西。还是非常感谢您。我应该删除答案吗? - Pishang Ujeniya
1
请仅返回翻译后的文本:不要删除,但详细说明您的库如何解决问题。 - 4b0
@Shree更新了答案,并提供了更多正确来源的信息。 非常感谢。 - Pishang Ujeniya
1
我撤回了我的标记。现在你的答案是存活。 - 4b0
@Shree 我现在意识到什么叫做幸福。 - Pishang Ujeniya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接