3

我正在尝试为我正在尝试制作的简单游戏执行面部跟踪。我正在使用处理。

我使用 OpenCV 使用 Haar Cascades 进行简单的人脸检测。但是,随着时间的推移,它在平滑跟踪面部方面存在问题。此外,它不会检测到倾斜的脸。

通过一些谷歌搜索,我发现我必须实施卡尔曼滤波器来平滑面部跟踪。但是,这是我第一次听说卡尔曼滤波器,我很难实现它。

我在处理中将这个库用于 OpenCV:https ://github.com/atduskgreg/opencv-processing

如果有人能告诉我如何使用 Processing 或 Java 实现卡尔曼滤波器(因为这个库基于 Java API),那将非常有帮助。

这是我用于人脸检测的代码。这是图书馆的示例草图之一:

import gab.opencv.*;
import processing.video.*;
import java.awt.*;

Capture video;
OpenCV opencv;

void setup() {
  size(640, 480);
  video = new Capture(this, 640/2, 480/2);
  opencv = new OpenCV(this, 640/2, 480/2);
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);  

  video.start();
}

void draw() {
  background(255);
  scale(2);
  opencv.loadImage(video);

  image(video, 0, 0 );

  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);
  Rectangle[] faces = opencv.detect();  
  println(faces.length);

  for (int i = 0; i < faces.length; i++) {
    println(faces[i].x + "," + faces[i].y);
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
  }
}

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

1 回答 1

0

我还没有设法移植威廉链接到的卡尔曼滤波器 c++ 示例,因为并非所有来自 c++ api 的函数都存在于 OpenCV java 包装器中,所以就我所知:

import gab.opencv.*;
import processing.video.*;
import java.awt.*;

import org.opencv.core.*;
import org.opencv.video.*;

int w = 640;
int h = 480;
int hw = w/2;
int hh = h/2;

Capture video;
OpenCV opencv;

/*
Mat img(500, 500, CV_8UC3);
KalmanFilter KF(4, 2, 0);
Mat_<float> state(4, 1); // (x, y, Vx, Vy) 
Mat processNoise(4, 1, CV_32F);
Mat_<float> measurement(2,1); measurement.setTo(Scalar(0));
*/
Mat img;
KalmanFilter KF;
Mat processNoise;
MatOfFloat state,measurement;

void setup() {
  size(w, h);
  video = new Capture(this, hw, hh);
  opencv = new OpenCV(this, hw, hh);
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
  video.start();

  img = new Mat(w,h,CvType.CV_8UC3);
  KF = new KalmanFilter(4,2,0,CvType.CV_32F);
  state = new MatOfFloat(4,1);
}

void draw() {
  background(255);
  scale(2);
  opencv.loadImage(video);

  image(video, 0, 0 );

  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);
  Rectangle[] faces = opencv.detect();  
  if(faces.length > 0)
     rect(faces[0].x,faces[0].y,faces[0].width,faces[0].height);
}

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

statePre正如您所注意到的,我并没有像或transitionMatrix不可见的属性那样走得太远。

虽然不一样,但可能有点平均可能会有所帮助:

import gab.opencv.*;
import processing.video.*;
import java.awt.*;

int w = 640;
int h = 480;
int hw = w/2;
int hh = h/2;

Capture video;
OpenCV opencv;

int historySize = 10;
Rectangle[] history;

void setup() {
  size(w, h);
  video = new Capture(this, hw, hh);
  opencv = new OpenCV(this, hw, hh);
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
  video.start();
  setupHistory();
}
void setupHistory(){
  history = new Rectangle[historySize];
  for(int i = 0 ; i  < historySize ; i++) history[i] = new Rectangle();
}
void keyPressed(){
  if(key == 'h' && historySize > 1) {
    noLoop();
    historySize--;
    setupHistory();
    loop();
  }
  if(key == 'H') {
    noLoop();
    historySize++;
    setupHistory();
    loop();
  }
  println(historySize);  
}

void draw() {
  background(255);
  scale(2);
  opencv.loadImage(video);

  image(video, 0, 0 );

  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);
  Rectangle[] faces = opencv.detect();  
  if(faces.length > 0){
     Rectangle f = mousePressed ? average(faces[0]) : faces[0];
     rect(f.x,f.y,f.width,f.height);
  }
}

void captureEvent(Capture c) {
  c.read();
}
Rectangle average(Rectangle newFace){
  Rectangle avg = new Rectangle();
  for(int i = historySize - 1; i > 0; i--){
    history[i] = history[i-1];
    avg.x += history[i].x;
    avg.y += history[i].y;
    avg.width += history[i].width;
    avg.height += history[i].height;
  }
  history[0] = newFace;
  avg.x += history[0].x;
  avg.y += history[0].y;
  avg.width += history[0].width;
  avg.height += history[0].height;
  avg.x /= historySize;
  avg.y /= historySize;
  avg.width /= historySize;
  avg.height /= historySize;
  return avg;
}

按住鼠标可以看到平滑的结果。使用H键来增加和h减少历史记录大小。

于 2013-12-16T11:45:17.410 回答