使用JavaCV实现人脸检测+训练+识别(实时视频检测)

前言

在我自己的另一个java项目中想添加一个人脸识别模块,但是在网上搜寻了很多后资料后发现使用java实现人脸识别的例子几乎没有(用C++实现的特别多,用java的真的很少,虽然有很多类似标题的文章,但是经本人尝试很多都实现不了或者有很多小问题),经过自己的不断摸索,终于用JavaCV实现了人脸识别,这篇文章尽可能的详细说明实现过程。

一些说明

  1. 环境:系统Win10,编译环境eclipse,JavaCV1.4.4
  2. 说明:JavaCV内置了OpenCV,本次实现就是利用内置的OpenCV 的 facerecognizer分类器实现人脸训练的。需要特殊注意的一点是,虽然JavaCV内置了OpenCV,但是不代表JavaCV中的Opencv等于独立的OpenCV,再次强调,JavaCV中的OpenCV不等于单独的OpenCV!使用过程中一定不可以混用(也就是import的时候注意名称问题);
  3. 此外,如果想单独通过OpenCV来实现当时也是可行的,但是最新版本的OpenCV把face模块给独立出来扔到扩展包里面去了,所以正常安装OpenCV然后配置环境是没法调用的,还需要重新编译扩展包,总之很麻烦,不建议。。。

样本训练+测试

1.使用facerecognizer分类器进行训练,对分类器不熟悉的可以自行百度,这里不过多介绍分类器,而是着重介绍java代码

package FacePack1;

import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_face.*;
import static org.bytedeco.javacpp.opencv_imgproc.*;
import static org.bytedeco.javacpp.opencv_objdetect.*;
import java.nio.IntBuffer;
import java.util.List;
import java.util.Vector;
import javax.swing.JFrame;
import org.bytedeco.javacpp.opencv_imgcodecs;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.javacpp.IntPointer;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber.Exception;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.javacv.OpenCVFrameGrabber;



public class Training {

	public static void main(String[] args)  {
		//准备两个人的训练图片,每个人脸十张
		//需要注意,训练的图片必须是相同大小的灰度图

		//读取图片保存到mat	
	    Mat y1 = opencv_imgcodecs.imread("y_one.jpg",0);
	    Mat y2 = opencv_imgcodecs.imread("y_two.jpg",0);
	    Mat y3 = opencv_imgcodecs.imread("y_three.jpg",0);
	    Mat y4 = opencv_imgcodecs.imread("y_four.jpg",0);
	    Mat y5 = opencv_imgcodecs.imread("y_five.jpg",0);
	    Mat y6 = opencv_imgcodecs.imread("y_six.jpg",0);
	    Mat y7 = opencv_imgcodecs.imread("y_seven.jpg",0);
	    Mat y8 = opencv_imgcodecs.imread("y_eight.jpg",0);
	    Mat y9 = opencv_imgcodecs.imread("y_nine.jpg",0);
	    Mat y10 = opencv_imgcodecs.imread("y_ten.jpg",0);
	    	  
	    Mat y11 = opencv_imgcodecs.imread("l_one.jpg",0);
	    Mat y12 = opencv_imgcodecs.imread("l_two.jpg",0);
	    Mat y13 = opencv_imgcodecs.imread("l_three.jpg",0);
	    Mat y14 = opencv_imgcodecs.imread("l_four.jpg",0);
	    Mat y15 = opencv_imgcodecs.imread("l_five.jpg",0);
	    Mat y16 = opencv_imgcodecs.imread("l_six.jpg",0);
	    Mat y17 = opencv_imgcodecs.imread("l_seven.jpg",0);
	    Mat y18 = opencv_imgcodecs.imread("l_eight.jpg",0);
	    Mat y19 = opencv_imgcodecs.imread("l_nine.jpg",0);
	    Mat y20 = opencv_imgcodecs.imread("l_ten.jpg",0);
	   	    		
		MatVector images =new MatVector(20);//一共20个训练样本
		Mat lables = new Mat(20,1,CV_32SC1);//对应20个标签值		
		//写入标签值,前十个为1,后十个为2
		IntBuffer lablesBuf = lables.createBuffer();	
		lablesBuf.put(0, 1);
		lablesBuf.put(1, 1);
		lablesBuf.put(2, 1);
		lablesBuf.put(3, 1);
		lablesBuf.put(4, 1);
		lablesBuf.put(5, 1);
		lablesBuf.put(6, 1);
		lablesBuf.put(7, 1);
		lablesBuf.put(8, 1);
		lablesBuf.put(9, 1);
		lablesBuf.put(10, 2);
		lablesBuf.put(11, 2);
		lablesBuf.put(12, 2);
		lablesBuf.put(13, 2);
		lablesBuf.put(14, 2);
		lablesBuf.put(15, 2);
		lablesBuf.put(16, 2);
		lablesBuf.put(17, 2);
		lablesBuf.put(18, 2);
		lablesBuf.put(19, 2);
				
		//写入图片				
		images.put(0,y1);
		images.put(1,y2);
		images.put(2,y3);
		images.put(3,y4);
		images.put(4,y5);
		images.put(5,y6);
		images.put(6,y7);
		images.put(7,y8);
		images.put(8,y9);
		images.put(9,y10);
		images.put(10,y11);
		images.put(11,y12);
		images.put(12,y13);
		images.put(13,y14);
		images.put(14,y15);
		images.put(15,y16);
		images.put(16,y17);
		images.put(17,y18);
		images.put(18,y19);
		images.put(19,y20);
		
		//创建人脸分类器,有Fisher、Eigen、LBPH,选哪种自己决定,这里使用FisherFaceRecognizer											
		FaceRecognizer fr = FisherFaceRecognizer.create();
		//训练
		fr.train(images, lables);	
		//保存训练结果	
		fr.save("FisherRecognize.xml");
				
		//读取训练出的xml文件
		fr.read("FisherRecognize.xml");
		//设置阈值,阈值为0则任何人都不认识,阈值特别大的时候任何人都认识(返回和样本最相似的结果,永远不会返回-1)
		//前面忘记说了,检测返回-1代表不能和训练结果匹配
		fr.setThreshold(3000.0);		
		
		
		//*********************测试部分************************
				               
        //开启摄像头,获取图像(得到的图像为frame类型,需要转换为mat类型进行检测和识别)
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        grabber.setImageWidth(640);
        grabber.setImageHeight(480);              
		grabber.start();
					
		CanvasFrame canvas = new CanvasFrame("人脸检测");//新建一个窗口  
	    canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
	    while(true)  
	    {  
	        if(!canvas.isEnabled())  
	        {//窗口是否关闭  
	            grabber.stop();//停止抓取  
	            System.exit(0);//退出  
	        }  
	    Frame frame=grabber.grab();
	    
	    OpenCVFrameConverter.ToMat convertor = new OpenCVFrameConverter.ToMat();//用于类型转换
	    Mat scr=convertor.convertToMat(frame);//将获取的frame转化成mat数据类型        	    
	    Mat grayscr=new Mat();
	    Mat face = new Mat();
	    Mat roi = new Mat();
		cvtColor(scr,grayscr,COLOR_BGRA2GRAY);//摄像头是彩色图像,所以先灰度化下
		equalizeHist(grayscr,grayscr);//均衡化直方图
		
  		//读取opencv人脸检测器,参考我的路径改为自己的路径
  		CascadeClassifier cascade = new CascadeClassifier(
				"D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
		//检测人脸
		RectVector faces=new RectVector();
		cascade.detectMultiScale(grayscr, faces);
		
		IntPointer label = new IntPointer(1);
        DoublePointer confidence = new DoublePointer(1);
        
        //识别人脸
		for(int i=0;i<faces.size();i++)
		{
			Rect face_i=faces.get(i);
			rectangle(scr, face_i, new Scalar(0, 255, 0, 1));
			
			roi = new Mat(grayscr,face_i);
			resize(roi, face, new Size(350, 350));//我的训练样本是350*350,要对应的进行修改
			fr.predict(face, label, confidence);									
	        int predictedLabel = label.get(0);//得到识别的标签值
	        
	        //判断并显示	        
	        if(predictedLabel==1)
	        {String box_text = "people:YangPeng";
	        int pos_x = Math.max(face_i.tl().x() - 10, 0);
            int pos_y = Math.max(face_i.tl().y() - 10, 0);        
            putText(scr, box_text, new Point(pos_x, pos_y),
                    FONT_HERSHEY_PLAIN, 1.0, new Scalar(0, 255, 0, 2.0));
	        }
	        else if (predictedLabel==2)
	        {
	        	int pos_x = Math.max(face_i.tl().x() - 10, 0);
	            int pos_y = Math.max(face_i.tl().y() - 10, 0);
	            // And now put it into the image:
	            putText(scr, "people:LiPengpeng", new Point(pos_x, pos_y),
	                    FONT_HERSHEY_PLAIN, 1.0, new Scalar(0, 255, 0, 2.0));
	        }
	        else
	        {
	        	int pos_x = Math.max(face_i.tl().x() - 10, 0);
	            int pos_y = Math.max(face_i.tl().y() - 10, 0);
	            // And now put it into the image:
	            putText(scr, "UnknownPeople!", new Point(pos_x, pos_y),
	                    FONT_HERSHEY_PLAIN, 1.0, new Scalar(0, 0, 255, 2.0));
	        }                      
		}
		
		//显示
        frame=convertor.convert(scr);//将检测结果重新的mat重新转化为frame
        canvas.showImage(frame);//获取摄像头图像并放到窗口上显示,frame是一帧视频图像  
        Thread.sleep(20);//20毫秒刷新一次图像 

	    
	    }	    
	}	
}

测试结果截图

在这里插入图片描述

不懂的地方欢迎一起交流,转载请注明出处。

  • 7
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值