Java implementa un ejemplo completo de inicio de sesión de reconocimiento facial con OpenCV

Me inscribí para participar en el primer desafío del Proyecto Golden Stone: comparta el premio acumulado de 100,000, este es mi primer artículo, haga clic para ver los detalles del evento

OpenCV

Vista previa del efecto

inserte la descripción de la imagen aquí

Visión general

OpenCV (Open Source Computer Vision Library) se publica bajo la licencia BSD (Open Source License). Es una biblioteca altamente optimizada enfocada en aplicaciones en tiempo real. Tiene interfaces C++, Python y Java y es compatible con Windows, Linux, Mac OS, iOS y Android.

Descargar e instalar

enlace de descarga:https://opencv.org/releases/

inserte la descripción de la imagen aquí

Después de descargar al local, haga doble clic para instalar

inserte la descripción de la imagen aquí

Directorio Descripción

El directorio de instalación es el siguiente

inserte la descripción de la imagen aquí

build :基于window构建

sources:开源,提供源码
复制代码

descripción del directorio de compilación

inserte la descripción de la imagen aquí

Aquí está el enfoque de desarrollo de Java en el directorio de Java

inserte la descripción de la imagen aquí

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

opencv-460.jar给java操作openvc的程序包
复制代码

Dado que es un sistema de 64 bits, preste atención al directorio x64

inserte la descripción de la imagen aquí

El archivo DLL (Biblioteca de vínculos dinámicos) es un archivo de biblioteca de vínculos dinámicos, también conocido como "extensión de aplicación", que es un tipo de archivo de software. Archivos DLL, colocados en el sistema. Cuando se ejecuta un programa, se llamará al archivo DLL correspondiente

Uso básico de OpenCV

Dirección del documento del sitio web oficial:https://docs.opencv.org/4.6.0/df/d65/tutorial_table_of_content_introduction.html

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

Referencia del tutorial:https://www.w3cschool.cn/opencv/

Referencia del tutorial:https://www.yiibai.com/opencv/opencv_adding_text.html

Integración de proyectos

Aquí se utiliza IDEA para el desarrollo y se importa la biblioteca opencv-460.jar

Utilice el acceso directo Ctrl+Shift+Alt+S para abrir inserte la descripción de la imagen aquíSeleccione el elemento de la biblioteca e importe la biblioteca de Java.inserte la descripción de la imagen aquí inserte la descripción de la imagen aquí

Además de los métodos anteriores, también puede opencv-460.jarinstalar en un repositorio local o en un repositorio privado y luego introducir dependencias en pom.xml.

Imagen de detección de rostros

    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);
    }
复制代码

inserte la descripción de la imagen aquí

Similitud de contraste facial

对比1.jpg与1-1.jpg

对比1.jpg与3.jpg
复制代码

inserte la descripción de la imagen aquí

    // 初始化人脸探测器
    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;
    }
复制代码

Los resultados de la comparación son los siguientes

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

Identificar rostros en videos

    // 初始化人脸探测器
    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;
    }

复制代码

inserte la descripción de la imagen aquí

La cámara reconoce la cara.

    // 初始化人脸探测器
    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;
    }
复制代码

ventana personalizada

La interfaz gráfica de usuario HighGUI con OpenCV siente que hay muy pocos parámetros configurables, por lo que se usa una ventana personalizable en su lugar.

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生成GUI
            frame = 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;
    }
}
复制代码

La cámara captura el video y lo escribe en el local.

    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 integra OpenCV

agregar dependencias

    <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>
复制代码

Integración de proyectos OpenCV

Integración del proyecto OpenCV consulte lo OpenCV的基本使用anterior项目集成

interfaz de solicitud

@Controller
@RequestMapping("/user")
public class UserFaceLogin  {

    @Autowired
    private MyJPanel myJPanel;

    @RequestMapping("/login")
    public String login() throws Exception {
        // 调用摄像头显示
        boolean  result = myJPanel.cameraFaceRecognition();
        if (result) {
            return "/success.html";
        } else {
            return "/error.html";
        }
    }
}
复制代码

configurar aplicación.yml

El entorno de desarrollo y el entorno de producción deben distinguirse

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

Especificar los parámetros de la máquina virtual

-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

Complete el trabajo de inicialización y agregue la función de coincidencia de rostros, y se pueden extender más funciones a esta clase de herramienta.

@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");


    @Override
    public 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;
    }
}
复制代码

ventana personalizada

La ventana personalizada se utiliza para obtener la toma de cámara en tiempo real

@Component
public class MyJPanel extends JPanel {

    @Autowired
    private 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生成GUI
            frame = 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;
    }
}
复制代码

Crear página

Cree una página Index.html que simule el inicio de sesión facial y una página de salto exitosa de inicio de sesión facial éxito.html y una página de salto fallida de inicio de sesión facial error.html

índice.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>
复制代码

exito.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>
复制代码

Configuración de clase de inicio

Se encontró una excepción durante el proceso de desarrollo, es decir, al usar una ventana personalizada, debe modificar la clase de inicio, la configuración .setHeadless(false)o agregar parámetros de JVM -Djava.awt.headless=falsepara resolverlo.

@SpringBootApplication
public class FaceOpenCvApplication {

    public static void main(String[] args) {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(FaceOpenCvApplication.class);
        builder.headless(false).run(args);
    }
}
复制代码

Registros de excepciones comunes

excepción 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)
复制代码

Copie el D:\Development\opencv\build\java\x64\opencv_java460.dllarchivo en los siguientes dos directorios, elija uno de ellos.

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

excepción 2

java.lang.Exception: unknown exception
	org.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)
复制代码

Configurar la ruta de la biblioteca de clases

Ingrese D:\Development\opencv\build\x64\vc15\bin, obtenga la ruta y inserte la descripción de la imagen aquíagregue configuración de parámetros de ejecución de JVM

-Djava.library.path=D:\Development\opencv\build\java\x64
复制代码

o

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

excepción 3

En lugar de reiniciar Tomcat, deje que Tomcat reinicie automáticamente el paquete war.

java.lang.UnsatisfiedLinkError: Native Library D:\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)
复制代码

excepción 4

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.videoio.VideoCapture.VideoCapture_5(I)J
	at org.opencv.videoio.VideoCapture.VideoCapture_5(Native Method)
	at org.opencv.videoio.VideoCapture.<init>(VideoCapture.java:181)
复制代码

No olvide cargar la biblioteca nativa de OpenCV

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

excepción 5

java.lang.UnsatisfiedLinkError: org.opencv.objdetect.CascadeClassifier.CascadeClassifier_1(Ljava/lang/String;)J
	at 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]
复制代码

Afectado por las spring-boot-devtoolsdependencias, esta dependencia se excluyó inicialmente y era normal después de limpiar el proyecto. Posteriormente, se agregó esta dependencia y el resultado no se vio afectado. Tenga en cuenta que cuando se modifica la configuración, todavía hay muchos proyectos limpios, como sin respuesta y otras condiciones anormales.

excepción 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)
复制代码

Modificar la clase de inicio, establecer.setHeadless(false);

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

O establezca los parámetros de la máquina virtual JVM

-Djava.awt.headless=false
复制代码

Acho que você gosta

Origin juejin.im/post/7139739779519905806
Recomendado
Clasificación