javacv进阶opencv图像检测/识别系列
人脸检测识别
JavaCV进阶opencv图像处理:摄像头图像人脸检测
JavaCV进阶opencv图像处理:ffmpeg视频图像画面人脸检测
JavaCV进阶opencv图像处理:批量人脸图像分类训练
JavaCV进阶opencv图像处理:摄像头图像人脸识别
二维码识别
JavaCV进阶opencv图像处理:扫描并识别摄像头中的二维码
JavaCV进阶opencv图像处理:10行代码快速实现扫描识别图片中的二维码
JavaCV进阶opencv图像处理:扫描并识别视频中的二维码
前言
上一章已经讲了如何通过OpenCVFrameGrabber读取摄像头画面来进行图像检测,javacv官方的教程也是这样,在上一章的基础上可以自行扩展支持视频的图像检测。
本章基于FFmpegFrameGrabber读取视频图像并使用opnecv进行图像检测,并且只获取视频,过滤掉音频。
FFmpegFrameGrabber中的Frame转换
在博主JavaCV入门指南:调用opencv原生API和JavaCV是如何封装了opencv的图像处理操作文章中关于Frame的结构分析:
只有使用非OpenCVFrameGrabber的抓取器才需要使用转换器进行转换,Frame里面的一个字段opaque引用了Mat等数据,所以可以直接从Frame中直接获得Mat,不需要再进行转换了。
与上一章的OpenCVFrameGrabber中的opaque字段里面引用的是Mat结构体不同的是,FFmpegFrameGrabber中的opaque字段一般引用的是ffmpeg中的AVFrame结构体,所以是需要使用工具进行转换的,需要使用OpenCVFrameConverter把Frame转换为Mat,然后进行人脸检测,在后续的人脸识别中也将会用到。
功能实现
1、使用FFmpegFrameGrabber获取视频图像画面,过滤音频,之抓取视频图像
2、使用OpenCVFrameConverter把Frame转换为Mat
3、使用opencv的Haar cascade正面人脸分类器进行人脸检测
Haar cascade分类检测库文件下载:
代码实现
/**
* 人脸检测
* @param input 视频源
* @param cascadeClassifierXml 基于Haar特征的cascade正面人脸分类器
* @param width 图像宽度
* @param height 图像高度
*/
public static void ffmpegFaceDetection(String input,String cascadeClassifierXml,Integer width,Integer height) throws Exception, InterruptedException {
// 读取视频文件或者视频流获取图像(得到的图像为frame类型,需要转换为mat类型进行检测和识别)
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(input);
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();
}
//Frame与Mat转换器
OpenCVFrameConverter.ToMat converter=new OpenCVFrameConverter.ToMat();
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);
//ffmpegFrameGrabber读取图片与视频不同的是,图片只需要调用一次grabber.grabImage()即可,视频需要循环一直调用,直到没有视频帧为止。
//只获取图像帧
for(;canvas.isVisible()&&(frame=grabber.grabImage())!=null;) {
//FFmpegFrameGrabber获取的opaque是AvFrame,所以需要转换
Mat img =converter.convert(frame);// 将获取的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, 0, 255, 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是一帧视频图像
}
cascade.close();
canvas.dispose();
grabber.close();// 停止抓取
}
运行代码
这里的测试地址博主使用的是本地文件,大家可以替换成rtsp、rtmp或者hls等等直播或者录播地址即可
public static void main(String[] args) throws Exception, InterruptedException {
ffmpegFaceDetection("file:d://video/eguid.mp4","haarcascade_frontalface_alt.xml",0,0);
}
下一章是opencv人脸识别或者是opencv模型训练