0


Java借助OpenCV实现人脸识别登录完整示例

Java借助OpenCV实现人脸识别登录完整示例

OpenCV

效果预览

在这里插入图片描述

概述

OpenCV(开源计算机视觉库)是在BSD(开源协议)许可下发布的。它是一个高度优化的库,专注于实时应用程序。它具有C ++,Python和Java接口,支持Windows,Linux,Mac OS,iOS和Android。

下载与安装

下载地址:

https://opencv.org/releases/

在这里插入图片描述

下载到本地后,双击进行安装即可

在这里插入图片描述

目录说明

安装目录如下

在这里插入图片描述

build :基于window构建

sources:开源,提供源码

build目录说明

在这里插入图片描述

这里是Java开发关注java目录即可

在这里插入图片描述

x64与x86代表给不同的系统使用

opencv-460.jar给java操作openvc的程序包

由于是64位系统,所以关注x64目录

在这里插入图片描述

DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。DLL文件,放置于系统中。当执行某一个程序时,相应的DLL文件就会被调用

OpenCV的基本使用

官网文档地址:

https://docs.opencv.org/4.6.0/df/d65/tutorial_table_of_content_introduction.html

中文文档:

http://wiki.opencv.org.cn/index.php

教程参考:

https://www.w3cschool.cn/opencv/

教程参考:

https://www.yiibai.com/opencv/opencv_adding_text.html

项目集成

这里使用IDEA进行开发,导入opencv-460.jar库

使用快捷键 Ctrl+Shift+Alt+S打开
在这里插入图片描述
选择库项,导入Java库。
在这里插入图片描述
在这里插入图片描述

除了上述方式,还可以将

opencv-460.jar

安装到本地仓库或私有仓库,然后在pom.xml中引入依赖。

图片人脸检测

    public static void main(String[] args){imageFaceDetection();}/**
     * 图片人脸检测
     */
    public static void imageFaceDetection(){// 加载OpenCV本地库
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
        CascadeClassifier faceDetector =newCascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");// 读取测试图片
        String imgPath ="D:\\user\\test.png";
        Mat image = Imgcodecs.imread(imgPath);if(image.empty()){thrownewRuntimeException("图片内存为空");}// 检测脸部
        MatOfRect face =newMatOfRect();// 检测图像中的人脸
        faceDetector.detectMultiScale(image, face);// 匹配Rect矩阵
        Rect[] rects = face.toArray();
        System.out.println("识别人脸个数: "+ rects.length);// 识别图片中的所以人脸并分别保存
        int i =1;for(Rect rect : 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,"D:\\user\\"+ i +".jpg", rect.x, rect.y, rect.width, rect.height);
            i++;}// 图片中人脸画框保存到本地
        Imgcodecs.imwrite("D:\\user\\test1.png", image);// 展示图片
        HighGui.imshow("人脸识别", image);
        HighGui.waitKey(0);}/**
     * 裁剪人脸
     *
     * @param readPath 读取文件路径
     * @param outPath  写出文件路径
     * @param x        坐标X
     * @param y        坐标Y
     * @param width    截图宽度
     * @param height   截图长度
     */
    public static void imageCut(String readPath, String outPath, int x, int y, int width, int height){// 原始图像
        Mat image = Imgcodecs.imread(readPath);// 截取的区域
        Rect rect =newRect(x, y, width, height);// Mat sub = new Mat(image,rect);
        Mat sub = image.submat(rect);
        Mat mat =newMat();
        Size size =newSize(width, height);// 人脸进行截图并保存
        Imgproc.resize(sub, mat, size);
        Imgcodecs.imwrite(outPath, mat);}

在这里插入图片描述

人脸对比相似度

对比1.jpg与1-1.jpg

对比1.jpg与3.jpg

在这里插入图片描述

// 初始化人脸探测器staticCascadeClassifier faceDetector;static{// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
        faceDetector =newCascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}publicstaticvoidmain(String[] args){double comparison =faceRecognitionComparison("D:\\user\\1.jpg","D:\\user\\1-1.jpg");System.out.println("对比结果:"+ comparison);if(comparison >0.85){System.out.println("人脸匹配成功");}else{System.out.println("人脸不匹配识别");}double comparison2 =faceRecognitionComparison("D:\\user\\1.jpg","D:\\user\\3.jpg");System.out.println("对比结果:"+ comparison2);if(comparison2 >0.85){System.out.println("人脸匹配成功");}else{System.out.println("人脸不匹配识别");}// 终止当前运行的 Java 虚拟机。System.exit(0);}/**
     * 人脸识别比对
     */publicstaticdoublefaceRecognitionComparison(String image1,String image2){Mat mat1 =conv_Mat(image1);Mat mat2 =conv_Mat(image2);Mat mat3 =newMat();Mat mat4 =newMat();// 颜色范围MatOfFloat ranges =newMatOfFloat(0f,256f);// 直方图大小, 越大匹配越精确 (越慢)MatOfInt histSize =newMatOfInt(1000);Imgproc.calcHist(Arrays.asList(mat1),newMatOfInt(0),newMat(), mat3, histSize, ranges);Imgproc.calcHist(Arrays.asList(mat2),newMatOfInt(0),newMat(), mat4, histSize, ranges);// 比较两个密集或两个稀疏直方图returnImgproc.compareHist(mat3, mat4,Imgproc.CV_COMP_CORREL);}/**
     * 灰度化人脸
     */publicstaticMatconv_Mat(String img){// 读取图像Mat mat1 =Imgcodecs.imread(img);Mat mat2 =newMat();// 灰度化:将图像从一种颜色空间转换为另一种颜色空间Imgproc.cvtColor(mat1, mat2,Imgproc.COLOR_BGR2GRAY);// 探测人脸:检测到的对象作为矩形列表返回MatOfRect faceDetections =newMatOfRect();
        faceDetector.detectMultiScale(mat1, faceDetections);// rect中人脸图片的范围for(Rect rect : faceDetections.toArray()){Mat face =newMat(mat1, rect);return face;}returnnull;}

对比结果如下

对比结果:1.0
人脸匹配成功
对比结果:0.2501351968792374
人脸不匹配识别

识别视频中的人脸

// 初始化人脸探测器staticCascadeClassifier faceDetector;static{// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
        faceDetector =newCascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}publicstaticvoidmain(String[] args){videoFaceRecognition();// 终止当前运行的 Java 虚拟机。System.exit(0);}/**
     * 从视频中识别人脸
     */publicstaticvoidvideoFaceRecognition(){// 读取视频文件VideoCapture capture =newVideoCapture();
        capture.open("D:\\user\\test.mp4");if(!capture.isOpened()){thrownewRuntimeException("读取视频文件失败");}Mat video =newMat();int index =0;while(capture.isOpened()){// 抓取、解码并返回下一个视频帧写入Mat对象中
            capture.read(video);// 显示从视频中识别的人脸图像HighGui.imshow("视频识别人脸",getFace(video));// 获取键盘输入
            index =HighGui.waitKey(100);// 如果是 Esc 则退出if(index ==27){
                capture.release();return;}}}/**
     * 从视频帧中识别人脸
     *
     * @param image 待处理Mat图片,即视频中的某一帧
     * @return 处理后的图片
     */publicstaticMatgetFace(Mat image){MatOfRect face =newMatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。
        faceDetector.detectMultiScale(image, face);Rect[] rects = face.toArray();System.out.println("识别人脸个数: "+ rects.length);if(rects.length >0&&Math.random()*10>8){Imgcodecs.imwrite("D:\\user\\"+ UUID.randomUUID()+".png", image);}if(rects !=null&& rects.length >=1){// 为每张识别到的人脸画一个圈for(int i =0; i < rects.length; i++){/**
                 * 绘制一个简单的、粗的或填充的直角矩形
                 *
                 * img 图像
                 * pt1 - 矩形的顶点
                 * pt2 - 与 pt1 相对的矩形的顶点
                 * color – 矩形颜色或亮度(灰度图像)意味着该函数必须绘制一个填充的矩形。
                 */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));/**
                 * 绘制一个文本字符串,放在识别人脸框上
                 *
                 * img -- 图像
                 * text -- 要绘制的文本字符串
                 * org – 图像中文本字符串的左下角
                 * fontFace – 字体类型,请参阅#HersheyFonts
                 * fontScale – 字体比例因子乘以特定字体的基本大小
                 * color - 文本颜色
                 * thickness ——用于绘制文本的线条粗细
                 * lineType – 线型
                 * bottomLeftOrigin – 当为 true 时,图像数据原点位于左下角。否则,它位于左上角
                 */Imgproc.putText(image,"test",newPoint(rects[i].x, rects[i].y),Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX,1.0,newScalar(0,255,0),1,Imgproc.LINE_AA,false);}}return image;}

在这里插入图片描述

摄像头识别人脸

// 初始化人脸探测器staticCascadeClassifier faceDetector;static{// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
        faceDetector =newCascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}publicstaticvoidmain(String[] args)throwsException{cameraFaceRecognition();// 终止当前运行的 Java 虚拟机。System.exit(0);}/**
     * 摄像头实时人脸识别
     *
     * @throws Exception
     */publicstaticvoidcameraFaceRecognition()throwsException{// 打开摄像头获取视频流,0 打开默认摄像头VideoCapture videoCapture =newVideoCapture(0);// 检查是否支持摄像头  true:代表摄像头可以打开  false:不可以打开System.out.println(videoCapture.isOpened());// 获取摄像头高度int height =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT);// 获取摄像头宽度int width =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH);if(height ==0|| width ==0){thrownewException("摄像头不存在");}Mat video =newMat();int index =0;if(videoCapture.isOpened()){while(true){
                videoCapture.read(video);HighGui.imshow("实时人脸识别",getFace(video));// 键盘输入
                index =HighGui.waitKey(50);// 是Esc则退出,比强制退出好if(index ==27){// 写入人脸Imgcodecs.imwrite("D:\\user\\"+"face.png", video);
                    videoCapture.release();return;}}}}/**
     * 从视频帧中识别人脸
     *
     * @param image 待处理Mat图片,即视频中的某一帧
     * @return 处理后的图片
     */publicstaticMatgetFace(Mat image){MatOfRect face =newMatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。
        faceDetector.detectMultiScale(image, face);Rect[] rects = face.toArray();System.out.println("识别人脸个数: "+ rects.length);if(rects !=null&& rects.length >=1){// 为每张识别到的人脸画一个圈for(int i =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,"test",newPoint(rects[i].x, rects[i].y),Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX,1.0,newScalar(0,255,0),1,Imgproc.LINE_AA,false);}}return image;}

自定义窗口

OpenCV带的HighGUI图形用户界面感觉可配置参数太少,因此可自定义窗口用于代替。

importorg.opencv.core.Point;importorg.opencv.core.*;importorg.opencv.imgcodecs.Imgcodecs;importorg.opencv.imgproc.Imgproc;importorg.opencv.objdetect.CascadeClassifier;importorg.opencv.videoio.VideoCapture;importorg.opencv.videoio.Videoio;importjavax.swing.*;importjava.awt.*;importjava.awt.image.BufferedImage;publicclassMyJPanelextendsJPanel{privateBufferedImage mImg;// 初始化人脸探测器staticCascadeClassifier faceDetector;staticVideoCapture videoCapture;staticJFrame frame;static{// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
        faceDetector =newCascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}publicvoidpaintComponent(Graphics g){if(mImg !=null){
            g.drawImage(mImg,0,0, mImg.getWidth(), mImg.getHeight(),this);}}/**
     * 摄像头识别人脸
     */publicstaticvoidcameraFaceRecognition()throwsException{try{// 打开摄像头获取视频流,0 打开默认摄像头
            videoCapture =newVideoCapture(0);// 检查是否支持摄像头  true:代表摄像头可以打开  false:不可以打开System.out.println(videoCapture.isOpened());// 获取摄像头高度int height =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT);// 获取摄像头宽度int width =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH);if(height ==0|| width ==0){thrownewException("摄像头不存在");}//使用Swing生成GUI
            frame =newJFrame("人脸识别");
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);MyJPanel panel =newMyJPanel();//设置中心显示
            frame.setContentPane(panel);
            frame.setVisible(true);
            frame.setSize(width + frame.getInsets().left + frame.getInsets().right, height + frame.getInsets().top + frame.getInsets().bottom);
            frame.setLocationRelativeTo(null);// 创建矩阵Mat capImg =newMat();// 创建一个临时矩阵Mat temp =newMat();while(frame.isShowing()){//从摄像头读取一帧数据,保存到capImg矩阵中。
                videoCapture.read(capImg);//转换为彩色图Imgproc.cvtColor(capImg, temp,Imgproc.COLOR_RGBA2BGRA);// 人脸识别
                capImg =getFace(capImg);// 本地图片保存Imgcodecs.imwrite("D:\\user\\1.jpg", capImg);//转为图像显示
                panel.mImg = panel.matToImage(capImg);// 重绘此组件
                panel.repaint();}}finally{// 关闭摄像头
            videoCapture.release();
            frame.dispose();}}/**
     * 从视频帧中识别人脸
     *
     * @param image 待处理Mat图片,即视频中的某一帧
     * @return 处理后的图片
     */publicstaticMatgetFace(Mat image){MatOfRect face =newMatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。
        faceDetector.detectMultiScale(image, face);Rect[] rects = face.toArray();System.out.println("识别人脸个数: "+ rects.length);if(rects !=null&& rects.length >=1){// 为每张识别到的人脸画一个圈for(int i =0; i < rects.length; i++){// 绘制一个简单的、粗的或填充的直角矩形Imgproc.rectangle(image,neworg.opencv.core.Point(rects[i].x, rects[i].y),neworg.opencv.core.Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height),newScalar(0,255,0));// 绘制一个文本字符串,放在识别人脸框上Imgproc.putText(image,"test",newPoint(rects[i].x, rects[i].y),Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX,1.0,newScalar(0,255,0),1,Imgproc.LINE_AA,false);}}return image;}/**
     * 转换图像
     */privateBufferedImagematToImage(Mat mat){int dataSize = mat.cols()* mat.rows()*(int) mat.elemSize();byte[] data =newbyte[dataSize];
        mat.get(0,0, data);int type = mat.channels()==1?BufferedImage.TYPE_BYTE_GRAY :BufferedImage.TYPE_3BYTE_BGR;if(type ==BufferedImage.TYPE_3BYTE_BGR){for(int i =0; i < dataSize; i +=3){byte blue = data[i +0];
                data[i +0]= data[i +2];
                data[i +2]= blue;}}BufferedImage image =newBufferedImage(mat.cols(), mat.rows(), type);
        image.getRaster().setDataElements(0,0, mat.cols(), mat.rows(), data);return image;}}

摄像头拍摄视频写入本地

publicstaticvoidmain(String[] args)throwsException{MyJPanel.cameraFaceRecognition();// 终止当前运行的 Java 虚拟机。System.exit(0);}
// 初始化人脸探测器staticCascadeClassifier faceDetector;staticBufferedImage mImg;static{// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中
        faceDetector =newCascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}publicstaticvoidmain(String[] args)throwsException{writeVideo();// 终止当前运行的 Java 虚拟机。System.exit(0);}/**
     * 摄像头拍摄视频写入本地
     */publicstaticvoidwriteVideo()throwsException{// 打开摄像头获取视频流,0 打开默认摄像头VideoCapture videoCapture =newVideoCapture(0);// 检查是否支持摄像头  true:代表摄像头可以打开  false:不可以打开System.out.println(videoCapture.isOpened());// 获取摄像头高度int height =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT);// 获取摄像头宽度int width =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH);if(height ==0|| width ==0){thrownewException("摄像头不存在");}Mat video =newMat();int index =0;Size size =newSize(videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH), videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT));VideoWriter writer =newVideoWriter("D:\\user\\1.mp4",VideoWriter.fourcc('D','I','V','X'),30.0, size,true);while(videoCapture.isOpened()){//从摄像头读取一帧数据,保存到capImg矩阵中。
            videoCapture.read(video);
            writer.write(video);HighGui.imshow("视频人脸识别", video);// 获取键盘输入
            index =HighGui.waitKey(100);// 是Esc则退出,若强制退出将导致录制视频无法播放if(index ==27){
                videoCapture.release();
                writer.release();return;}}}

Spring Boot集成OpenCV

添加依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies>

项目集成OpenCV

项目集成OpenCV参考上述

OpenCV的基本使用

中的

项目集成

请求接口

@Controller@RequestMapping("/user")publicclassUserFaceLogin{@AutowiredprivateMyJPanel myJPanel;@RequestMapping("/login")publicStringlogin()throwsException{// 调用摄像头显示boolean  result = myJPanel.cameraFaceRecognition();if(result){return"/success.html";}else{return"/error.html";}}}

配置application.yml

开发环境与生产环境需区分

opencv:
  lib:
    linuxxmlpath:/usr/local//opencv/haarcascades/haarcascade_frontalface_alt.xml
    windowxmlpath:D:\Development\opencv\sources\data\haarcascades\haarcascade_frontalface_alt.xml

指定虚拟机参数

-Djava.library.path=D:\Development\opencv\build\java\x64

或

-Djava.library.path=D:\Development\opencv\build\java\x64;D:\Development\opencv\build\x64\vc15\bin

OpenCvUtil

完成初始化工作以及添加人脸匹配功能,更多功能扩展此工具类即可。

@ComponentpublicclassOpenCvUtilimplementsCommandLineRunner{// 初始化人脸探测器staticCascadeClassifier faceDetector;@Value("${opencv.lib.linuxxmlpath}")privateString linuxXmlPath;@Value("${opencv.lib.windowxmlpath}")privateString windowXmlPath;/**
     * 判断是否是Windows系统
     */privatestaticfinalboolean IS_WINDOWS =System.getProperty("os.name").toLowerCase().contains("win");@Overridepublicvoidrun(String... args){System.loadLibrary(Core.NATIVE_LIBRARY_NAME);String path ="";if(IS_WINDOWS){
            path = windowXmlPath;}else{
            path = linuxXmlPath;}/**
         * 初始化人脸探测器
         */
        faceDetector =newCascadeClassifier(path);}publicstaticintmatch(String loginImagePath,String comparedImagePath){Mat mat1 =conv_Mat(loginImagePath);if(mat1 ==null){return0;}Mat mat2 =conv_Mat(comparedImagePath);Mat mat3 =newMat();Mat mat4 =newMat();// 颜色范围MatOfFloat ranges =newMatOfFloat(0f,256f);// 直方图大小, 越大匹配越精确 (越慢)MatOfInt histSize =newMatOfInt(1000);Imgproc.calcHist(Arrays.asList(mat1),newMatOfInt(0),newMat(), mat3, histSize, ranges);Imgproc.calcHist(Arrays.asList(mat2),newMatOfInt(0),newMat(), mat4, histSize, ranges);// 比较两个密集或两个稀疏直方图Double score =Imgproc.compareHist(mat3, mat4,Imgproc.CV_COMP_CORREL);System.out.println("score "+ score);if(score >=0.8){return1;}return0;}publicstaticMatconv_Mat(String img){// 读取图像Mat mat1 =Imgcodecs.imread(img);Mat mat2 =newMat();// 灰度化:将图像从一种颜色空间转换为另一种颜色空间Imgproc.cvtColor(mat1, mat2,Imgproc.COLOR_BGR2GRAY);// 探测人脸:检测到的对象作为矩形列表返回MatOfRect faceDetections =newMatOfRect();
        faceDetector.detectMultiScale(mat1, faceDetections);// rect中人脸图片的范围for(Rect rect : faceDetections.toArray()){Mat face =newMat(mat1, rect);return face;}returnnull;}}

自定义窗口

自定义窗口用于实时获取摄像头拍摄画面

@ComponentpublicclassMyJPanelextendsJPanel{@AutowiredprivateOpenCvUtil openCvUtil;privateBufferedImage mImg;privateVideoCapture videoCapture;privateJFrame frame;publicvoidpaintComponent(Graphics g){if(mImg !=null){
            g.drawImage(mImg,0,0, mImg.getWidth(), mImg.getHeight(),this);}}/**
     * 摄像头识别人脸
     */publicBooleancameraFaceRecognition()throwsException{try{// 打开摄像头获取视频流,0 打开默认摄像头
            videoCapture =newVideoCapture(0);// 检查是否支持摄像头  true:代表摄像头可以打开  false:不可以打开System.out.println(videoCapture.isOpened());// 获取摄像头高度int height =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT);// 获取摄像头宽度int width =(int) videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH);if(height ==0|| width ==0){thrownewException("摄像头不存在");}// 使用Swing生成GUI
            frame =newJFrame("人脸识别");
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);MyJPanel panel =newMyJPanel();//设置中心显示
            frame.setContentPane(panel);
            frame.setVisible(true);
            frame.setSize(width + frame.getInsets().left + frame.getInsets().right, height + frame.getInsets().top + frame.getInsets().bottom);
            frame.setLocationRelativeTo(null);// 创建矩阵Mat capImg =newMat();// 创建一个临时矩阵Mat temp =newMat();// 对比图片String comparedImagePath ="D:\\user\\"+"compared.jpg";// 摄像头拍摄图片String loginImagePath ="D:\\user\\"+"login.jpg";int tag =0;while(frame.isShowing()&& tag <5){
                tag++;//从摄像头读取一帧数据,保存到capImg矩阵中。
                videoCapture.read(capImg);//转换为彩色图Imgproc.cvtColor(capImg, temp,Imgproc.COLOR_RGBA2BGRA);// 人脸识别
                capImg =this.getFace(capImg);// 本地图片保存Imgcodecs.imwrite(loginImagePath, capImg);//转为图像显示
                panel.mImg = panel.matToImage(capImg);// 重绘组件
                panel.repaint();int result =OpenCvUtil.match(loginImagePath, comparedImagePath);if(result ==1){returntrue;}}}catch(Exception e){
            e.printStackTrace();}finally{// 关闭窗口if(frame !=null){
                frame.dispose();}//  关闭摄像头if(videoCapture !=null){
                videoCapture.release();}}returnfalse;}/**
     * 从视频帧中识别人脸
     *
     * @param image 待处理Mat图片,即视频中的某一帧
     * @return 处理后的图片
     */publicMatgetFace(Mat image){MatOfRect face =newMatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。
        openCvUtil.faceDetector.detectMultiScale(image, face);Rect[] rects = face.toArray();System.out.println("识别人脸个数: "+ rects.length);if(rects !=null&& rects.length >=1){// 为每张识别到的人脸画一个圈for(int i =0; i < rects.length; i++){// 绘制一个简单的、粗的或填充的直角矩形Imgproc.rectangle(image,neworg.opencv.core.Point(rects[i].x, rects[i].y),neworg.opencv.core.Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height),newScalar(0,255,0));// 绘制一个文本字符串,放在识别人脸框上Imgproc.putText(image,"test",newPoint(rects[i].x, rects[i].y),Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX,1.0,newScalar(0,255,0),1,Imgproc.LINE_AA,false);}}return image;}/**
     * 转换图像
     */privateBufferedImagematToImage(Mat mat){int dataSize = mat.cols()* mat.rows()*(int) mat.elemSize();byte[] data =newbyte[dataSize];
        mat.get(0,0, data);int type = mat.channels()==1?BufferedImage.TYPE_BYTE_GRAY :BufferedImage.TYPE_3BYTE_BGR;if(type ==BufferedImage.TYPE_3BYTE_BGR){for(int i =0; i < dataSize; i +=3){byte blue = data[i +0];
                data[i +0]= data[i +2];
                data[i +2]= blue;}}BufferedImage image =newBufferedImage(mat.cols(), mat.rows(), type);
        image.getRaster().setDataElements(0,0, mat.cols(), mat.rows(), data);return image;}}

创建页面

创建模拟人脸登录的页面Index.html以及人脸登录成功跳转页面success.html和人脸登录失败跳转页面error.html

index.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div id="index"class="tab-pane"><a href="/user/login">人脸登录</a></div></body></html>

success.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div><h3>人脸识别登录成功</h3></div></body></html>

error.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><div><h3>人脸识别登录失败</h3></div></body></html>

启动类配置

在开发过程中遇到一个异常,即使用自定义窗口时,需要修改启动类,设置

.setHeadless(false)

,或添加JVM参数

-Djava.awt.headless=false

来解决。

@SpringBootApplicationpublicclassFaceOpenCvApplication{publicstaticvoidmain(String[] args){SpringApplicationBuilder builder =newSpringApplicationBuilder(FaceOpenCvApplication.class);
        builder.headless(false).run(args);}}

常见异常记录

异常1

Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java460 in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
    at java.lang.Runtime.loadLibrary0(Runtime.java:871)
    at java.lang.System.loadLibrary(System.java:1122)

D:\Development\opencv\build\java\x64\opencv_java460.dll

文件拷贝至下面2个目录,任选其一即可。

在这里插入图片描述

在这里插入图片描述

异常2

java.lang.Exception: unknown exception
    org.opencv.videoio.VideoCapture.VideoCapture_3(NativeMethod)org.opencv.videoio.VideoCapture.<init>(VideoCapture.java:62)com.boxuegu.servlet.UserFaceLogin.doGet(UserFaceLogin.java:25)javax.servlet.http.HttpServlet.service(HttpServlet.java:635)javax.servlet.http.HttpServlet.service(HttpServlet.java:742)org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

配置类库路径

进入

D:\Development\opencv\build\x64\vc15\bin

,获取该路径
在这里插入图片描述
添加JVM运行参数配置

-Djava.library.path=D:\Development\opencv\build\java\x64

或者

-Djava.library.path=D:\Development\opencv\build\java\x64;D:\Development\opencv\build\x64\vc15\bin

异常3

没重启Tomcat,而是让Tomcat自动重启war包导致

java.lang.UnsatisfiedLinkError:NativeLibraryD:\Development\opencv\build\java\x64\opencv_java460.dll already loaded in another classloader
    java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1900)java.lang.ClassLoader.loadLibrary(ClassLoader.java:1850)java.lang.Runtime.loadLibrary0(Runtime.java:871)java.lang.System.loadLibrary(System.java:1122)com.boxuegu.servlet.UserFaceLogin.doGet(UserFaceLogin.java:24)javax.servlet.http.HttpServlet.service(HttpServlet.java:635)javax.servlet.http.HttpServlet.service(HttpServlet.java:742)org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

异常4

Exception in thread "main"java.lang.UnsatisfiedLinkError:org.opencv.videoio.VideoCapture.VideoCapture_5(I)J
    at org.opencv.videoio.VideoCapture.VideoCapture_5(NativeMethod)
    at org.opencv.videoio.VideoCapture.<init>(VideoCapture.java:181)

别忘了加载OpenCV本地库

static{// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

异常5

java.lang.UnsatisfiedLinkError:org.opencv.objdetect.CascadeClassifier.CascadeClassifier_1(Ljava/lang/String;)J
    at org.opencv.objdetect.CascadeClassifier.CascadeClassifier_1(NativeMethod)~[opencv-460.jar:4.6.0]
    at org.opencv.objdetect.CascadeClassifier.<init>(CascadeClassifier.java:48)~[opencv-460.jar:4.6.0]

spring-boot-devtools

依赖影响,最初排除此依赖,clean项目后正常。后来又加上此依赖,结果又不影响,注意当修改配置后没反应等异常情况还是多clean项目。

异常6

java.awt.HeadlessException
    at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204)
    at java.awt.Window.<init>(Window.java:536)
    at java.awt.Frame.<init>(Frame.java:420)
    at javax.swing.JFrame.<init>(JFrame.java:233)

修改启动类,设置

.setHeadless(false);
@SpringBootApplicationpublicclassFaceOpenCvApplication{publicstaticvoidmain(String[] args){SpringApplicationBuilder builder =newSpringApplicationBuilder(FaceOpenCvApplication.class);
        builder.headless(false).run(args);}}

或者设置JVM虚拟机参数

-Djava.awt.headless=false

本文转载自: https://blog.csdn.net/qq_38628046/article/details/126455814
版权归原作者 CodeDevMaster 所有, 如有侵权,请联系我们删除。

“Java借助OpenCV实现人脸识别登录完整示例”的评论:

还没有评论