Java使用opencv实现人脸识别、人脸比对
发布时间:2025-06-24 16:45:50 作者:北方职教升学中心 阅读量:375
1. opencv概述
OpenCV是一个开源的计算机视觉库,它提供了一系列丰富的图像处理和计算机视觉算法,包括图像读取、显示、滤波、特征检测、目标跟踪等功能。
opencv官网:https://opencv.org/
opencv官网文档:https://docs.opencv.org/4.7.0/index.html
参考教程1:https://www.w3cschool.cn/opencv/
参考教程2:https://www.yiibai.com/opencv/opencv_adding_text.html
2. 安装opencv
2.1 下载opencv
opencv下载:https://opencv.org/releases/
这里我们使用4.7.0版本,下载到本地后,双击进行安装即可。
进入到opencv的安装目录:
build :基于window构建sources:开源,提供源码
进入到build\java 目录
x64与x86目录下是对应的.dll文件:代表给不同的系统使用,下面的代码会使用到.dll文件
opencv-460.jar给java操作openvc的程序包
2.2 准备文件
# 1. 特征分类器:windows 和 linux 中的配置文件都一样,随便用哪个都行haarcascade_frontalface_alt.xml# windows 路径 : opencv\build\etc\haarcascades# linux 路径 : /usr/local/share/opencv4/haarcascades# 2. jar 包 - 也可以直接使用 javacv 中的 opencv 包opencv-470.jar# windows 路径 : {opencv安装目录}\opencv\build\java# linux 路径 : /usr/local/share/java/opencv4# 3. 动态库opencv_java470.dll (windows系统使用此文件)# windows 路径 : {opencv安装目录}\opencv\build\java\{x64}/{x86} 跟据系统选择libopencv_java470.so (linux系统使用此文件)# linux 路径 : /usr/local/share/java/opencv4
3. 代码实现
3.1 pom.xml添加依赖
<!-- 版本的依赖与下载的opencv版本一致--><dependency><groupId>org.bytedeco</groupId><artifactId>opencv</artifactId><version>4.7.0-1.5.9</version></dependency>
或:
<dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.9</version></dependency>
或:
<dependency><groupId>org.openpnp</groupId><artifactId>opencv</artifactId><version>4.7.0-0</version></dependency>
以上三个依赖任选其一即可,项目打包后观察一下使用哪个依赖打包后的jar文件更小
实验证明:
javacv-platform依赖的jar最大,达到929.64M
org.openpnp.opencv依赖最小,几乎为0M
org.bytedeco.opencv依赖居中,大小为2M
ps:依赖包太大,优化参考:https://blog.csdn.net/u014644574/article/details/122067708
3.2 编写代码
ps:代码中存在加载.dll、haarcascade_frontalface_alt.xml文件,请确保文件地址正确
packagecom.testpro.test.opencv;importorg.opencv.core.*;importorg.opencv.imgcodecs.Imgcodecs;importorg.opencv.imgproc.Imgproc;importorg.opencv.objdetect.CascadeClassifier;importjava.util.Arrays;publicclassFaceCompare{// 初始化人脸探测器staticCascadeClassifierfaceDetector;privatestaticfinalStringPATH_PREFIX="C:\\Users\\dev\\Desktop\\";staticinti =0;static{// 判断系统Stringos =System.getProperty("os.name");// 加载动态库if(os !=null&&os.toLowerCase().startsWith("windows")){// Windows操作系统// todo windows 系统部署加载 .dll 文件 - 路径跟据自己存放位置更改【这里需要使用绝对路径】System.load("D:\opencv\opencv\build\java\x64\opencv_java470.dll");}elseif(os !=null&&os.toLowerCase().startsWith("linux")){// Linux操作系统// todo Linux 服务器部署加载 .so 文件 - 路径跟据自己存放位置更改【是否需要绝对路径有待验证,目前只在windows 系统实践过】System.load("/opt/face/libopencv_java440.so");}// 引入 特征分类器配置 文件:haarcascade_frontalface_alt.xml 文件路径// 此文件在opencv的安装目录build\etc\haarcascades下可以找到Stringproperty ="D:\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml";System.out.println(property);faceDetector =newCascadeClassifier(property);}publicstaticvoidmain(String[]args){// 图片路径不能包含中文Stringstr1 =PATH_PREFIX+"3-1.jpg";Stringstr2 =PATH_PREFIX+"3-2.jpg";longstart =System.currentTimeMillis();doublecompareHist =compare_image(str1,str2);System.out.println("time:"+(System.currentTimeMillis()-start));System.out.println(compareHist);if(compareHist >0.6){System.out.println("人脸匹配");}else{System.out.println("人脸不匹配");}}// 灰度化人脸publicstaticMatconv_Mat(Stringimg){Matimage0 =Imgcodecs.imread(img);Matimage1 =newMat();// 灰度化Imgproc.cvtColor(image0,image1,Imgproc.COLOR_BGR2GRAY);// 探测人脸MatOfRectfaceDetections =newMatOfRect();faceDetector.detectMultiScale(image1,faceDetections);// rect中人脸图片的范围for(Rectrect :faceDetections.toArray()){Matface =newMat(image1,rect);returnface;}returnnull;}// 比较图片publicstaticdoublecompare_image(Stringimg_1,Stringimg_2){Matmat_1 =conv_Mat(img_1);Matmat_2 =conv_Mat(img_2);Mathist_1 =newMat();Mathist_2 =newMat();//颜色范围MatOfFloatranges =newMatOfFloat(0f,256f);//直方图大小, 越大匹配越精确 (越慢)MatOfInthistSize =newMatOfInt(10000000);Imgproc.calcHist(Arrays.asList(mat_1),newMatOfInt(0),newMat(),hist_1,histSize,ranges);Imgproc.calcHist(Arrays.asList(mat_2),newMatOfInt(0),newMat(),hist_2,histSize,ranges);// CORREL 相关系数doubleres =Imgproc.compareHist(hist_1,hist_2,Imgproc.CV_COMP_CORREL);returnres;}}
上述代码加载.dll文件也可使用以下方式:
ps:【不过以下方式需要将opencv安装目录下的build\java\x64\opencv_java470.dll文件复制到C:\Windows\System32目录下才可使用否则会报错】
// 使用此方法需将D:\opencv\opencv\build\java\x64\opencv_java470.dll文件复制到C:\Windows\System32目录下System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
如下:
4. 效果
5. 附:完整代码
包括:
从摄像头实时人脸识别,识别成功保存图片到本地
从本地视频文件中识别人脸
本地图片人脸识别,识别成功并保存人脸图片到本地
packagecom.testpro.test.opencv;importorg.opencv.core.*;importorg.opencv.highgui.HighGui;importorg.opencv.imgcodecs.Imgcodecs;importorg.opencv.imgproc.Imgproc;importorg.opencv.objdetect.CascadeClassifier;importorg.opencv.videoio.VideoCapture;importorg.opencv.videoio.VideoWriter;importorg.opencv.videoio.Videoio;importjava.util.Arrays;/** * Opencv 图片人脸识别、实时摄像头人脸识别、视频文件人脸识别 */publicclassFaceVideo{// 初始化人脸探测器staticCascadeClassifierfaceDetector;staticinti =0;static{// 判断系统Stringos =System.getProperty("os.name");// 加载动态库if(os !=null&&os.toLowerCase().startsWith("windows")){// Windows操作系统// todo windows 系统部署加载 .dll 文件 - 路径跟据自己存放位置更改System.load("D:\opencv\opencv\build\java\x64\opencv_java470.dll");// ClassLoader.getSystemResource("dlls/opencv_java470.dll");}elseif(os !=null&&os.toLowerCase().startsWith("linux")){// Linux操作系统// todo Linux 服务器部署加载 .so 文件 - 路径跟据自己存放位置更改System.load("/opt/face/libopencv_java440.so");}// 引入 特征分类器配置 文件:haarcascade_frontalface_alt.xml 文件路径Stringproperty ="D:\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml";System.out.println(property);faceDetector =newCascadeClassifier(property);}privatestaticfinalStringPATH_PREFIX="C:\\Users\\dev\\Desktop\\";publicstaticvoidmain(String[]args){// 1- 从摄像头实时人脸识别,识别成功保存图片到本地// getVideoFromCamera();// 2- 从本地视频文件中识别人脸// getVideoFromFile();// 3- 本地图片人脸识别,识别成功并保存人脸图片到本地// face("5-1.jpg");// 4- 比对本地2张图的人脸相似度 (越接近1越相似)doublecompareHist =compare_image(PATH_PREFIX+"5-1.jpg",PATH_PREFIX+"6-1.jpg");System.out.println(compareHist);if(compareHist >0.72){System.out.println("人脸匹配");}else{System.out.println("人脸不匹配");}}/** * OpenCV-4.7.0 从摄像头实时读取 */publicstaticvoidgetVideoFromCamera(){//1 如果要从摄像头获取视频 则要在 VideoCapture 的构造方法写 0VideoCapturecapture =newVideoCapture(0);Matvideo =newMat();intindex =0;if(capture.isOpened()){while(i <3){// 匹配成功3次退出capture.read(video);HighGui.imshow("实时人脸识别",getFace(video));index =HighGui.waitKey(100);if(index ==27){capture.release();break;}}}else{System.out.println("摄像头未开启");}try{capture.release();Thread.sleep(1000);System.exit(0);}catch(InterruptedExceptione){e.printStackTrace();}return;}/** * OpenCV-4.7.0 从视频文件中读取 */publicstaticvoidgetVideoFromFile(){VideoCapturecapture =newVideoCapture();capture.open(PATH_PREFIX+"yimi.mp4");//1 读取视频文件的路径if(!capture.isOpened()){System.out.println("读取视频文件失败!");return;}Matvideo =newMat();intindex =0;while(capture.isOpened()){capture.read(video);//2 视频文件的视频写入 Mat video 中HighGui.imshow("本地视频识别人脸",getFace(video));//3 显示图像index =HighGui.waitKey(100);//4 获取键盘输入if(index ==27){//5 如果是 Esc 则退出capture.release();return;}}}/** * OpenCV-4.7.0 人脸识别 * * @param image 待处理Mat图片(视频中的某一帧) * @return 处理后的图片 */publicstaticMatgetFace(Matimage){// 1 读取OpenCV自带的人脸识别特征XML文件(faceDetector)// CascadeClassifier facebook = new CascadeClassifier("D:\\Sofeware\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");// 2 特征匹配类MatOfRectface =newMatOfRect();// 3 特征匹配faceDetector.detectMultiScale(image,face);Rect[]rects =face.toArray();System.out.println("匹配到 "+rects.length +" 个人脸");if(rects !=null&&rects.length >=1){// 4 为每张识别到的人脸画一个圈for(inti =0;i <rects.length;i++){Imgproc.rectangle(image,newPoint(rects[i].x,rects[i].y),newPoint(rects[i].x +rects[i].width,rects[i].y +rects[i].height),newScalar(0,255,0));Imgproc.putText(image,"Human",newPoint(rects[i].x,rects[i].y),Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX,1.0,newScalar(0,255,0),1,Imgproc.LINE_AA,false);//Mat dst=image.clone();//Imgproc.resize(image, image, new Size(300,300));}i++;if(i ==3){// 获取匹配成功第10次的照片Imgcodecs.imwrite(PATH_PREFIX+"face.png",image);}}returnimage;}/** * OpenCV-4.7.0 图片人脸识别 */publicstaticvoidface(Stringfilename){// 1 读取OpenCV自带的人脸识别特征XML文件// OpenCV 图像识别库一般位于 opencv\sources\data 下面// CascadeClassifier facebook=new CascadeClassifier("D:\\Sofeware\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");// 2 读取测试图片StringimgPath =PATH_PREFIX+filename;Matimage =Imgcodecs.imread(imgPath);if(image.empty()){System.out.println("image 内容不存在!");return;}// 3 特征匹配MatOfRectface =newMatOfRect();faceDetector.detectMultiScale(image,face);// 4 匹配 Rect 矩阵 数组Rect[]rects =face.toArray();System.out.println("匹配到 "+rects.length +" 个人脸");// 5 为每张识别到的人脸画一个圈inti =1;for(Rectrect :face.toArray()){Imgproc.rectangle(image,newPoint(rect.x,rect.y),newPoint(rect.x +rect.width,rect.y +rect.height),newScalar(0,255,0),3);imageCut(imgPath,PATH_PREFIX+i +".jpg",rect.x,rect.y,rect.width,rect.height);// 进行图片裁剪i++;}// 6 展示图片HighGui.imshow("人脸识别",image);HighGui.waitKey(0);}/** * 裁剪人脸 * * @param imagePath * @param outFile * @param posX * @param posY * @param width * @param height */publicstaticvoidimageCut(StringimagePath,StringoutFile,intposX,intposY,intwidth,intheight){// 原始图像Matimage =Imgcodecs.imread(imagePath);// 截取的区域:参数,坐标X,坐标Y,截图宽度,截图长度Rectrect =newRect(posX,posY,width,height);// 两句效果一样Matsub =image.submat(rect);// Mat sub = new Mat(image, rect);Matmat =newMat();Sizesize =newSize(width,height);Imgproc.resize(sub,mat,size);// 将人脸进行截图并保存Imgcodecs.imwrite(outFile,mat);System.out.println(String.format("图片裁切成功,裁切后图片文件为: %s",outFile));}/** * 人脸比对 * * @param img_1 * @param img_2 * @return */publicstaticdoublecompare_image(Stringimg_1,Stringimg_2){Matmat_1 =conv_Mat(img_1);Matmat_2 =conv_Mat(img_2);Mathist_1 =newMat();Mathist_2 =newMat();//颜色范围MatOfFloatranges =newMatOfFloat(0f,256f);//直方图大小, 越大匹配越精确 (越慢)MatOfInthistSize =newMatOfInt(1000);Imgproc.calcHist(Arrays.asList(mat_1),newMatOfInt(0),newMat(),hist_1,histSize,ranges);Imgproc.calcHist(Arrays.asList(mat_2),newMatOfInt(0),newMat(),hist_2,histSize,ranges);// CORREL 相关系数doubleres =Imgproc.compareHist(hist_1,hist_2,Imgproc.CV_COMP_CORREL);returnres;}/** * 灰度化人脸 * * @param img * @return */publicstaticMatconv_Mat(Stringimg){Matimage0 =Imgcodecs.imread(img);Matimage1 =newMat();// 灰度化Imgproc.cvtColor(image0,image1,Imgproc.COLOR_BGR2GRAY);// 探测人脸MatOfRectfaceDetections =newMatOfRect();faceDetector.detectMultiScale(image1,faceDetections);// rect中人脸图片的范围for(Rectrect :faceDetections.toArray()){Matface =newMat(image1,rect);returnface;}returnnull;}/** * OpenCV-4.7.0 将摄像头拍摄的视频写入本地 */publicstaticvoidwriteVideo(){//1 如果要从摄像头获取视频 则要在 VideoCapture 的构造方法写 0VideoCapturecapture =newVideoCapture(0);Matvideo =newMat();intindex =0;Sizesize =newSize(capture.get(Videoio.CAP_PROP_FRAME_WIDTH),capture.get(Videoio.CAP_PROP_FRAME_HEIGHT));VideoWriterwriter =newVideoWriter("D:/a.mp4",VideoWriter.fourcc('D','I','V','X'),15.0,size,true);while(capture.isOpened()){capture.read(video);//2 将摄像头的视频写入 Mat video 中writer.write(video);HighGui.imshow("像头获取视频",video);//3 显示图像index =HighGui.waitKey(100);//4 获取键盘输入if(index ==27){//5 如果是 Esc 则退出capture.release();writer.release();return;}}}}