先说一下javacv
JavaCV [1] 是一款基于JavaCPP [2] 调用方式(JNI的一层封装),由多种开源计算机视觉库组成的包装库,封装了包含FFmpeg、OpenCV、tensorflow、caffe、tesseract、libdc1394、OpenKinect、videoInput和ARToolKitPlus等在内的计算机视觉领域的常用库和实用程序类。
一、先学习如何使用javaCV获取视频,并且获取其中的一帧
package cc.eguid.javacv;
import javax.swing.JFrame;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.javacv.FrameGrabber.Exception;
import org.bytedeco.javacv.OpenCVFrameGrabber;
/**
* JavaCV调用本地摄像头实时图像视频
* @author eguid
* @date 2016年6月13日
* @since javacv1.2
*/
public class JavavcCameraTest{
public static void main(String[] args) throws Exception, InterruptedException{
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);//新建opencv抓取器,一般的电脑和移动端设备中摄像头默认序号是0,不排除其他情况
grabber.start();//开始获取摄像头数据
CanvasFrame canvas = new CanvasFrame("摄像头预览");//新建一个预览窗口
canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//窗口是否关闭
while(canvas.isDisplayable()){
/*获取摄像头图像并在窗口中显示,这里Frame frame=grabber.grab()得到是解码后的视频图像*/
canvas.showImage(grabber.grab());
}
grabber.close();//停止抓取
}
}
关键是,(1)获取摄像头。(2)建立一个Canvas,(3)用grabber.grab()输出解码后的图像,用Canvas.showImage显示。
二、学习使用分类器
这是一段经典代码,调用摄像头,然后通过分类器找到每帧图像中的人脸。在上面画框。就是这么简单。代码的关键是
CascadeClassifier cascade = new CascadeClassifier(cascadeClassifierXml);
记住,这里是我们下一节要去研究的,“分类器的训练”
import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_face.*;
import static org.bytedeco.opencv.global.opencv_imgproc.*;
import static org.bytedeco.opencv.global.opencv_objdetect.*;
/**
* JavaCV人脸检测
* @author eguid
*/
public class JavaCVFaceDetectTest{
/**
* JavaCV人脸检测
* @author eguid
* @param cascadeClassifierXml 基于Haar特征的cascade正面人脸分类器
* @param width 图像宽度
* @param height 图像高度
*/
public static void faceDetection(String cascadeClassifierXml,Integer width,Integer height) throws Exception, InterruptedException {
// 开启摄像头,获取图像(得到的图像为frame类型,需要转换为mat类型进行检测和识别)
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
if(width!=null&&width>1&&height!=null&&height>1) {
grabber.setImageWidth(width);
grabber.setImageHeight(height);
}
grabber.start();
if(width==null||height==null) {
height=grabber.getImageHeight();
width=grabber.getImageWidth();
}
CanvasFrame canvas = new CanvasFrame("人脸检测");// 新建一个预览窗口
canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.setVisible(true);
canvas.setFocusable(true);
//窗口置顶
if(canvas.isAlwaysOnTopSupported()) {
canvas.setAlwaysOnTop(true);
}
Frame frame =null;
// 读取opencv人脸检测器
CascadeClassifier cascade = new CascadeClassifier(cascadeClassifierXml);
for(;canvas.isVisible()&&(frame=grabber.grab())!=null;) {
Mat img = (Mat) frame.opaque;// 从frame中直接获取Mat
Mat grayImg = new Mat();//存放灰度图
//摄像头色彩模式设置成ImageMode.Gray下不需要再做灰度
cvtColor(img, grayImg, COLOR_BGRA2GRAY);// 摄像头获取的是彩色图像,所以先灰度化下
//如果要获取摄像头灰度图,可以直接对FrameGrabber进行设置grabber.setImageMode(ImageMode.GRAY);,grabber.grab()获取的都是灰度图
equalizeHist(grayImg, grayImg);// 均衡化直方图
// 检测到的人脸
RectVector faces = new RectVector();
cascade.detectMultiScale(grayImg, faces);
// 遍历人脸
for (int i = 0; i < faces.size(); i++) {
Rect face_i = faces.get(i);
//绘制人脸矩形区域,scalar色彩顺序:BGR(蓝绿红)
rectangle(img, face_i, new Scalar(0, 255, 0, 1));
int pos_x = Math.max(face_i.tl().x() - 10, 0);
int pos_y = Math.max(face_i.tl().y() - 10, 0);
// 在人脸矩形上方绘制提示文字
putText(img, "people face", new Point(pos_x, pos_y), FONT_HERSHEY_COMPLEX, 1.0,new Scalar(0, 0, 255, 2.0));
}
canvas.showImage(frame);// 获取摄像头图像并放到窗口上显示,frame是一帧视频图像
Thread.sleep(40);// 40毫秒刷新一次图像
}
cascade.close();
canvas.dispose();
grabber.close();// 停止抓取
}
}
三、如何训练分类器(Cascade)
从上面看,关键的问题是:如何提供不同的分类器。
这部分且听下回分解。