使用JavaCV进行人员检测
Mon 16 December 2013 by XiaomengZhaoJavaCV是OpenCV的Wrapper,通过JNI调用OpenCV,按理说JavaCV和OpenCV应该是等价的,但是JavaCV并不像最近比较新的使用python调用OpenCV那么完善,没有例子,没有API文档,在使用中间会遇到各种问题,特以此文来记录自己遇到的问题和如何解决。
1. 如何新建一个JavaCV的Maven工程
在pom.xml中加入:
标签<repostiories>
中加入javacv的远程仓库地址:
<repository>
<id>javacv repo</id>
<url> http://maven2.javacv.googlecode.com/git/</url>
</repository>
标签<dependencies>
中加入javacv的相关依赖:
<dependency>
<groupId>com.googlecode.javacv</groupId>
<artifactId>javacv</artifactId>
<version>0.6</version>
</dependency>
<dependency>
<groupId>com.googlecode.javacv</groupId>
<artifactId>javacv</artifactId>
<classifier>macosx-x86_64</classifier>
<version>0.6</version>
</dependency>
2. 如何改写OpenCV程序为JavaCV程序
请参考https://code.google.com/p/javacv/wiki/ConvertingOpenCV,然后再进行JavaCV程序的编写。
3. 使用JavaCV进行人员检测
本程序参考了python版本的OpenCV人员检测范例peopledetect.py.(╮(╯▽╰)╭ 爱python一辈子)
程序的基本逻辑是使用HOG进行人员检测,有两点比较tricky:
(1) 使用HOG检测会得到很多矩形,我们只想要最外面的矩形,即如果矩形A不在其他所有的矩形中,不被所有其他矩形所包含,我们就认为这个矩形是我们想要的。
(2) HOG一般返回的矩形都比实际的物体要大,所以我们收缩了矩形,使得它圈人圈的更精确。
下面是我的代码:
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import java.awt.event.KeyEvent;
import org.junit.Test;
import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.cpp.opencv_objdetect.HOGDescriptor;
public class PeopleDetectInImage {
//如果r在q中则返回true,否则返回false
public boolean inside(CvRect r, CvRect q){
int rx = r.x(), ry = r.y(), rw = r.width(), rh = r.height();
int qx = q.x(), qy = q.y(), qw = q.width(), qh = q.height();
return (rx > qx) && (ry > qy) && ((rx + rw) < (qx + qw)) && ((ry + rh) < (qy + qh));
}
//由于HOG描述子返回的矩形都比实际的物体大一点
// 所以我们缩小一下矩形已返回更好的结果
public IplImage draw_detection(CvRect r, IplImage img){
int x = r.x(), y = r.y(), w = r.width(), h = r.height();
int pad_w = (int) (0.15*w), pad_h = (int) (0.05*h);
cvRectangle(img, cvPoint(x+pad_w, y+pad_h),cvPoint(x+w-pad_w, y+h-pad_h), CvScalar.GREEN, 2, CV_AA, 0);
return img;
}
@Test
public void detect_peoples() throws Exception {
CanvasFrame canvasFrame = new CanvasFrame("HOG-Test");
HOGDescriptor hog = new HOGDescriptor();
hog.setSVMDetector(HOGDescriptor.getDefaultPeopleDetector());
IplImage frame = cvLoadImage("/Users/zhaoxm/InBUPT/test_pics/test.jpg");
IplImage frame_clone = null;
CvRect found=new CvRect();
hog.detectMultiScale(frame, found, 0, cvSize(8,8), cvSize(32, 32), 1.05,2);
System.out.println(found.capacity());
//找到最外面的矩形
for(int i=0;i<found.capacity();i++) {
CvRect r = found.position(i);
boolean sign = false; //true代表矩形是里面的,false代表矩形是最外面的
for(int j=0;j<found.capacity();j++) {
if(i != j){ //不是同一个矩形
CvRect q = found.position(j);
if(inside(r,q)){
System.out.println(r);
System.out.println(q);
sign = true;
break;
}
}
if(!sign){ //r是最外面的框框
frame = draw_detection(r,frame);
//cvRectangle(frame, cvPoint(r.x(), r.y()),cvPoint(r.x() + r.width(), r.y() + r.height()), CvScalar.GREEN, 2, CV_AA, 0);
}
}
}
cvSaveImage("/Users/zhaoxm/InBUPT/test_pics/peoples.png",frame);
canvasFrame.showImage(frame);
KeyEvent key = canvasFrame.waitKey(0);
if (key != null) {
cvReleaseImage(frame);
canvasFrame.dispose();
}
}
public static void main(String[] args) throws Exception {
PeopleDetectInImage detector = new PeopleDetectInImage();
detector.detect_peoples();
}
}
程序运行结果如下:
结果还算不错。其中最重要的函数是detectMultiScale
,具体每个参数的解释见OpenCV文档:
C++: void gpu::HOGDescriptor::detectMultiScale(const GpuMat& img, vector
& found_locations, double hit_threshold=0, Size win_stride=Size(), Size padding=Size(), double scale0=1.05, int group_threshold=2)¶ Parameters:
- img – Source image. See gpu::HOGDescriptor::detect() for type limitations.
- found_locations – Detected objects boundaries.
- hit_threshold – Threshold for the distance between features and SVM classifying plane. See gpu::HOGDescriptor::detect() for details.
- win_stride – Window stride. It must be a multiple of block stride.
- padding – Mock parameter to keep the CPU interface compatibility. It must be (0,0).
- scale0 – Coefficient of the detection window increase.
- group_threshold – Coefficient to regulate the similarity threshold. When detected, some objects can be covered by many rectangles. 0 means not to perform grouping. See groupRectangles() .