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

  • OpenCV
    • 效果预览
    • 概述
    • 下载与安装
    • 目录说明
  • OpenCV的基本使用
    • 项目集成
    • 图片人脸检测
    • 人脸对比相似度
    • 识别视频中的人脸
    • 摄像头识别人脸
    • 自定义窗口
    • 摄像头拍摄视频写入本地
  • Spring Boot集成OpenCV
    • 添加依赖
    • 项目集成OpenCV
    • 请求接口
    • 配置application.yml
    • OpenCvUtil
    • 自定义窗口
    • 创建页面
    • 启动类配置
  • 常见异常记录
    • 异常1
    • 异常2
    • 异常3
    • 异常4
    • 异常5
    • 异常6

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 = new CascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");// 读取测试图片String imgPath = "D:\\user\\test.png";Mat image = Imgcodecs.imread(imgPath);if (image.empty()) {throw new RuntimeException("图片内存为空");}// 检测脸部MatOfRect face = new MatOfRect();// 检测图像中的人脸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, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(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 = new Rect(x, y, width, height);// Mat sub = new Mat(image,rect);Mat sub = image.submat(rect);Mat mat = new Mat();Size size = new Size(width, height);// 人脸进行截图并保存Imgproc.resize(sub, mat, size);Imgcodecs.imwrite(outPath, mat);}

人脸对比相似度

对比1.jpg与1-1.jpg对比1.jpg与3.jpg

    // 初始化人脸探测器static CascadeClassifier faceDetector;static {// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中faceDetector = new CascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}public static void main(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);}/*** 人脸识别比对*/public static double faceRecognitionComparison(String image1, String image2) {Mat mat1 = conv_Mat(image1);Mat mat2 = conv_Mat(image2);Mat mat3 = new Mat();Mat mat4 = new Mat();// 颜色范围MatOfFloat ranges = new MatOfFloat(0f, 256f);// 直方图大小, 越大匹配越精确 (越慢)MatOfInt histSize = new MatOfInt(1000);Imgproc.calcHist(Arrays.asList(mat1), new MatOfInt(0), new Mat(), mat3, histSize, ranges);Imgproc.calcHist(Arrays.asList(mat2), new MatOfInt(0), new Mat(), mat4, histSize, ranges);// 比较两个密集或两个稀疏直方图return Imgproc.compareHist(mat3, mat4, Imgproc.CV_COMP_CORREL);}/*** 灰度化人脸*/public static Mat conv_Mat(String img) {// 读取图像Mat mat1 = Imgcodecs.imread(img);Mat mat2 = new Mat();// 灰度化:将图像从一种颜色空间转换为另一种颜色空间Imgproc.cvtColor(mat1, mat2, Imgproc.COLOR_BGR2GRAY);// 探测人脸:检测到的对象作为矩形列表返回MatOfRect faceDetections = new MatOfRect();faceDetector.detectMultiScale(mat1, faceDetections);// rect中人脸图片的范围for (Rect rect : faceDetections.toArray()) {Mat face = new Mat(mat1, rect);return face;}return null;}

对比结果如下

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

识别视频中的人脸

    // 初始化人脸探测器static CascadeClassifier faceDetector;static {// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中faceDetector = new CascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}public static void main(String[] args) {videoFaceRecognition();// 终止当前运行的 Java 虚拟机。System.exit(0);}/*** 从视频中识别人脸*/public static void videoFaceRecognition() {// 读取视频文件VideoCapture capture = new VideoCapture();capture.open("D:\\user\\test.mp4");if (!capture.isOpened()) {throw new RuntimeException("读取视频文件失败");}Mat video = new Mat();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 处理后的图片*/public static Mat getFace(Mat image) {MatOfRect face = new MatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。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, new Point(rects[i].x, rects[i].y), new Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(0, 255, 0));/*** 绘制一个文本字符串,放在识别人脸框上** img -- 图像* text -- 要绘制的文本字符串* org – 图像中文本字符串的左下角* fontFace – 字体类型,请参阅#HersheyFonts* fontScale – 字体比例因子乘以特定字体的基本大小* color - 文本颜色* thickness ——用于绘制文本的线条粗细* lineType – 线型* bottomLeftOrigin – 当为 true 时,图像数据原点位于左下角。否则,它位于左上角*/Imgproc.putText(image, "test", new Point(rects[i].x, rects[i].y), Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, 1.0, new Scalar(0, 255, 0), 1, Imgproc.LINE_AA, false);}}return image;}

摄像头识别人脸

    // 初始化人脸探测器static CascadeClassifier faceDetector;static {// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中faceDetector = new CascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}public static void main(String[] args) throws Exception {cameraFaceRecognition();// 终止当前运行的 Java 虚拟机。System.exit(0);}/*** 摄像头实时人脸识别** @throws Exception*/public static void cameraFaceRecognition() throws Exception {// 打开摄像头获取视频流,0 打开默认摄像头VideoCapture videoCapture = new VideoCapture(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) {throw new Exception("摄像头不存在");}Mat video = new Mat();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 处理后的图片*/public static Mat getFace(Mat image) {MatOfRect face = new MatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。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, new Point(rects[i].x, rects[i].y), new Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(0, 255, 0));// 绘制一个文本字符串,放在识别人脸框上Imgproc.putText(image, "test", new Point(rects[i].x, rects[i].y), Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, 1.0, new Scalar(0, 255, 0), 1, Imgproc.LINE_AA, false);}}return image;}

自定义窗口

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

import org.opencv.core.Point;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;public class MyJPanel extends JPanel {private BufferedImage mImg;// 初始化人脸探测器static CascadeClassifier faceDetector;static VideoCapture videoCapture;static JFrame frame;static {// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中faceDetector = new CascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}public void paintComponent(Graphics g) {if (mImg != null) {g.drawImage(mImg, 0, 0, mImg.getWidth(), mImg.getHeight(), this);}}/*** 摄像头识别人脸*/public static void cameraFaceRecognition() throws Exception {try {// 打开摄像头获取视频流,0 打开默认摄像头videoCapture = new VideoCapture(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) {throw new Exception("摄像头不存在");}//使用Swing生成GUIframe = new JFrame("人脸识别");frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);MyJPanel panel = new MyJPanel();//设置中心显示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 = new Mat();// 创建一个临时矩阵Mat temp = new Mat();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 处理后的图片*/public static Mat getFace(Mat image) {MatOfRect face = new MatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。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, new org.opencv.core.Point(rects[i].x, rects[i].y), new org.opencv.core.Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(0, 255, 0));// 绘制一个文本字符串,放在识别人脸框上Imgproc.putText(image, "test", new Point(rects[i].x, rects[i].y), Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, 1.0, new Scalar(0, 255, 0), 1, Imgproc.LINE_AA, false);}}return image;}/*** 转换图像*/private BufferedImage matToImage(Mat mat) {int dataSize = mat.cols() * mat.rows() * (int) mat.elemSize();byte[] data = new byte[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 = new BufferedImage(mat.cols(), mat.rows(), type);image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);return image;}
}

摄像头拍摄视频写入本地

    public static void main(String[] args) throws Exception {MyJPanel.cameraFaceRecognition();// 终止当前运行的 Java 虚拟机。System.exit(0);}
    // 初始化人脸探测器static CascadeClassifier faceDetector;static BufferedImage mImg;static {// 加载OpenCV本地库System.loadLibrary(Core.NATIVE_LIBRARY_NAME);// 从配置文件lbpcascade_frontalface.xml中创建一个人脸识别器,文件位于opencv安装目录中faceDetector = new CascadeClassifier("D:\\Development\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");}public static void main(String[] args) throws Exception {writeVideo();// 终止当前运行的 Java 虚拟机。System.exit(0);}/*** 摄像头拍摄视频写入本地*/public static void writeVideo() throws Exception {// 打开摄像头获取视频流,0 打开默认摄像头VideoCapture videoCapture = new VideoCapture(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) {throw new Exception("摄像头不存在");}Mat video = new Mat();int index = 0;Size size = new Size(videoCapture.get(Videoio.CAP_PROP_FRAME_WIDTH), videoCapture.get(Videoio.CAP_PROP_FRAME_HEIGHT));VideoWriter writer = new VideoWriter("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")
public class UserFaceLogin  {@Autowiredprivate MyJPanel myJPanel;@RequestMapping("/login")public String login() throws Exception {// 调用摄像头显示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.xmlwindowxmlpath: 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

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

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

自定义窗口

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

@Component
public class MyJPanel extends JPanel {@Autowiredprivate OpenCvUtil openCvUtil;private BufferedImage mImg;private VideoCapture videoCapture;private JFrame frame;public void paintComponent(Graphics g) {if (mImg != null) {g.drawImage(mImg, 0, 0, mImg.getWidth(), mImg.getHeight(), this);}}/*** 摄像头识别人脸*/public Boolean cameraFaceRecognition() throws Exception {try {// 打开摄像头获取视频流,0 打开默认摄像头videoCapture = new VideoCapture(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) {throw new Exception("摄像头不存在");}// 使用Swing生成GUIframe = new JFrame("人脸识别");frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);MyJPanel panel = new MyJPanel();//设置中心显示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 = new Mat();// 创建一个临时矩阵Mat temp = new Mat();// 对比图片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) {return true;}}} catch (Exception e) {e.printStackTrace();} finally {// 关闭窗口if (frame != null) {frame.dispose();}//  关闭摄像头if (videoCapture != null) {videoCapture.release();}}return false;}/*** 从视频帧中识别人脸** @param image 待处理Mat图片,即视频中的某一帧* @return 处理后的图片*/public Mat getFace(Mat image) {MatOfRect face = new MatOfRect();// 检测输入图像中不同大小的对象。检测到的对象作为矩形列表返回。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, new org.opencv.core.Point(rects[i].x, rects[i].y), new org.opencv.core.Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(0, 255, 0));// 绘制一个文本字符串,放在识别人脸框上Imgproc.putText(image, "test", new Point(rects[i].x, rects[i].y), Imgproc.FONT_HERSHEY_SCRIPT_SIMPLEX, 1.0, new Scalar(0, 255, 0), 1, Imgproc.LINE_AA, false);}}return image;}/*** 转换图像*/private BufferedImage matToImage(Mat mat) {int dataSize = mat.cols() * mat.rows() * (int) mat.elemSize();byte[] data = new byte[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 = new BufferedImage(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来解决。

@SpringBootApplication
public class FaceOpenCvApplication {public static void main(String[] args) {SpringApplicationBuilder builder = new SpringApplicationBuilder(FaceOpenCvApplication.class);builder.headless(false).run(args);}
}

常见异常记录

异常1

Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java460 in java.library.pathat 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 exceptionorg.opencv.videoio.VideoCapture.VideoCapture_3(Native Method)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: Native Library D:\Development\opencv\build\java\x64\opencv_java460.dll already loaded in another classloaderjava.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)Jat org.opencv.videoio.VideoCapture.VideoCapture_5(Native Method)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;)Jat org.opencv.objdetect.CascadeClassifier.CascadeClassifier_1(Native Method) ~[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.HeadlessExceptionat 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);

@SpringBootApplication
public class FaceOpenCvApplication {public static void main(String[] args) {SpringApplicationBuilder builder = new SpringApplicationBuilder(FaceOpenCvApplication.class);builder.headless(false).run(args);}
}

或者设置JVM虚拟机参数

-Djava.awt.headless=false

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

  1. Java使用OpenCV实现人脸识别

    通过OpenCV实现人脸识别,包括图片,视频,摄像头中人脸识别. 首先看一下效果(在网上随便找的一张图片): 下面开始说一下如何实现的: 第一步:  需要安装OpenCV 下载链接:https://o ...

  2. python带界面的人脸识别_PyQt5+Caffe+Opencv搭建人脸识别登录界面

    最近开始学习Qt,结合之前学习过的caffe一起搭建了一个人脸识别登录系统的程序,新手可能有理解不到位的情况,还请大家多多指教. 我的想法是用opencv自带的人脸检测算法检测出面部,利用caffe训 ...

  3. java调起本地摄像头,利用openCV进行人脸识别(一)

    嗨咯,又好久没有更新了.今天写个前阵子做的人脸识别程序.该程序客户端基于Jave JFrame 客户端的主要作用是,调用电脑的摄像头(我的直接调用笔记本摄像头),然后回显摄像头录取的信息,再利用ope ...

  4. java利用openCV进行人脸对比(三)

    之前写过用openCV识别人脸和训练模型,这次说说用模型文件来对比人脸 首先要调起本地摄像头,然后识别一下人脸,这个人脸框出来,再调用模型文件进行人脸对比,识别成功显示用户名在人脸框框上面 这次我把这 ...

  5. ubuntu anzhang java,在Ubuntu中实现人脸识别登录的完整步骤

    1.安装Howdy: howdy项目地址 sudo add-apt-repository ppa:boltgolt/howdy sudo apt update sudo apt install how ...

  6. java人脸识别_自从加了PC人脸识别登录功能,网站立马显得高大上

    之前不是做了个开源项目嘛,在做完GitHub登录后,想着再显得有逼格一点,说要再加个人脸识别登录,就我这佛系的开发进度,过了一周总算是抽时间安排上了. 源码在文末 其实最近对写文章有点小抵触,写的东西 ...

  7. 用PyQt5+Caffe+Opencv搭建一个人脸识别登录界面

    最近开始学习Qt,结合之前学习过的caffe一起搭建了一个人脸识别登录系统的程序,新手可能有理解不到位的情况,还请大家多多指教. 我的想法是用opencv自带的人脸检测算法检测出面部,利用caffe训 ...

  8. java实现人脸识别登录教程【含效果图】——前台+后台整合

    这个做的是基于百度调的人脸接口. 百度提供有一个开发文档:http://ai.baidu.com/docs#/Face-Detect/top, 文档有java实例代码,返回参数等. 可以直接到:htt ...

  9. Java + opencv 实现人脸识别,图片人脸识别、视频人脸识别、摄像头实时人脸识别

    搭建环境 opencv官网下载windows安装包 https://opencv.org/releases/ 选择最新版4.1.1 下载完成后是一个opencv-4.1.1-vc14_vc15.exe ...

最新文章

  1. linux 卸载 rtx,Ubuntu20.04系统卸载软件及清理系统垃圾缓存以及新力得
  2. Service的一些使用
  3. Google 超分辨率技术 RAISR:模糊图片瞬间变清晰,运算速度快十倍
  4. 今晚直播:非自回归神经机器翻译 | PhD Talk #24
  5. 日志读取_php作为websocket的客户端实时读取推送日志文件
  6. python3入门基础语法总结_Python基础语法总结
  7. 您应该如何改变数据科学教育
  8. 【初探移动前端开发03】jQuery Mobile(上)
  9. useGeneratedKeys的用法
  10. 总结几点Quartz的经验
  11. java socket 工具_java Socket简易聊天工具
  12. [学习笔记]斯坦纳树
  13. Android Debug方法
  14. 走进JavaWeb技术世界1:Web后端与J2EE的由来
  15. EditPlus 3编译运行设置
  16. DNF最新纯图色脚本框架2022-4-27
  17. 计算机专业考研北京有哪些学校,计算机考研北京地区学校大全!
  18. 区块链重塑经济与世界
  19. 怎样用Java求水仙花数和水仙花数的数量
  20. 本征图像分解:Retinex理论【转载】

热门文章

  1. python自动化下载_selenium+python自动化98--文件下载弹窗处理(PyKeyboard)
  2. antdv中时间选择器a-range-picker中英文混杂
  3. 均衡之刃这款球拍是谁创作的
  4. 学学jscode的超酷HTML5时钟
  5. 手机多图传输神器-快传正式版抢先评测
  6. LaTex字体加粗的方法
  7. 车站计算机连锁cad图,微机联锁系统站场平面图CAD的研究与开发
  8. 34、树莓派进行人体姿态检测并进行语音播报
  9. Reeds-Shepp曲线和Dubins曲线相关资料汇总
  10. 量化经典问题——多因子选股模型