2025/06/06日日志 Java使用OpenCV实现人脸识别与人脸比对

Java使用OpenCV实现人脸识别与人脸比对

1. OpenCV概述

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。它支持多种编程语言,包括C++、Python和Java,并广泛应用于图像识别、目标跟踪、视频分析等领域。

2. 安装OpenCV

2.1 下载OpenCV

OpenCV的最新版本可以从其官网下载。本文使用的是4.7.0版本。下载完成后,解压到本地目录。

  • 下载地址OpenCV Releases
  • 安装目录结构
    • build:基于Windows的构建文件。
    • sources:源码文件。

进入build/java目录,可以看到以下文件:

  • opencv-470.jar:Java操作OpenCV的程序包。
  • x64x86目录:包含对应的.dll文件(Windows系统)或.so文件(Linux系统)。

2.2 准备文件

为了使用OpenCV进行人脸识别,需要以下文件:

  • 特征分类器文件haarcascade_frontalface_alt.xml,用于人脸检测。
    • Windows路径:opencv\build\etc\haarcascades
    • Linux路径:/usr/local/share/opencv4/haarcascades
  • Java库文件opencv-470.jar
    • Windows路径:{opencv安装目录}\opencv\build\java
    • Linux路径:/usr/local/share/java/opencv4
  • 动态链接库文件
    • Windows:opencv_java470.dll
    • Linux:libopencv_java470.so

3. 代码实现

3.1 添加依赖

在Maven项目中,需要在pom.xml文件中添加OpenCV的依赖。以下是三种可选的依赖配置:

<!-- 方式1 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>opencv</artifactId>
    <version>4.7.0-1.5.9</version>
</dependency>

<!-- 方式2 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.9</version>
</dependency>

<!-- 方式3 -->
<dependency>
    <groupId>org.openpnp</groupId>
    <artifactId>opencv</artifactId>
    <version>4.7.0-0</version>
</dependency>

根据实际需求选择合适的依赖。实验表明,javacv-platform依赖的打包文件最大(约929.64MB),而org.openpnp.opencv依赖的打包文件最小(几乎为0MB)。

3.2 编写代码

以下是实现人脸识别和比对的完整代码示例:

package com.testpro.test.opencv;

import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.util.Arrays;

public class FaceCompare {

    // 初始化人脸探测器
    static CascadeClassifier faceDetector;

    private static final String PATH_PREFIX = "C:\\Users\\dev\\Desktop\\";
    static int i = 0;

    static {
        // 判断系统类型并加载动态库
        String os = System.getProperty("os.name");
        if (os != null && os.toLowerCase().startsWith("windows")) {
            // Windows系统
            System.load("D:\\opencv\\opencv\\build\\java\\x64\\opencv_java470.dll");
        } else if (os != null && os.toLowerCase().startsWith("linux")) {
            // Linux系统
            System.load("/opt/face/libopencv_java440.so");
        }

        // 加载特征分类器文件
        String property = "D:\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml";
        faceDetector = new CascadeClassifier(property);
    }

    public static void main(String[] args) {
        // 比较两张图片的人脸相似度
        String str1 = PATH_PREFIX + "3-1.jpg";
        String str2 = PATH_PREFIX + "3-2.jpg";
        long start = System.currentTimeMillis();
        double compareHist = 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("人脸不匹配");
        }
    }

    // 灰度化人脸并提取人脸区域
    public static Mat conv_Mat(String img) {
        Mat image0 = Imgcodecs.imread(img);
        Mat image1 = new Mat();
        Imgproc.cvtColor(image0, image1, Imgproc.COLOR_BGR2GRAY);
        MatOfRect faceDetections = new MatOfRect();
        faceDetector.detectMultiScale(image1, faceDetections);
        for (Rect rect : faceDetections.toArray()) {
            Mat face = new Mat(image1, rect);
            return face;
        }
        return null;
    }

    // 比较两张图片的人脸相似度
    public static double compare_image(String img_1, String img_2) {
        Mat mat_1 = conv_Mat(img_1);
        Mat mat_2 = conv_Mat(img_2);
        Mat hist_1 = new Mat();
        Mat hist_2 = new Mat();
        MatOfFloat ranges = new MatOfFloat(0f, 256f);
        MatOfInt histSize = new MatOfInt(1000);
        Imgproc.calcHist(Arrays.asList(mat_1), new MatOfInt(0), new Mat(), hist_1, histSize, ranges);
        Imgproc.calcHist(Arrays.asList(mat_2), new MatOfInt(0), new Mat(), hist_2, histSize, ranges);
        double res = Imgproc.compareHist(hist_1, hist_2, Imgproc.CV_COMP_CORREL);
        return res;
    }
}

4. 效果展示

运行上述代码后,程序会输出两张图片的人脸相似度。如果相似度大于0.6,则认为人脸匹配;否则不匹配。以下是运行效果的示例:

运行效果

5. 扩展功能

除了人脸比对,还可以实现以下功能:

  • 从摄像头实时人脸识别:通过VideoCapture类获取摄像头视频流,并实时识别人脸。
  • 从本地视频文件中识别人脸:读取本地视频文件并识别人脸。
  • 本地图片人脸识别:读取本地图片并识别人脸,同时保存人脸图片到本地。

以下是实现这些功能的代码片段:

// 从摄像头实时人脸识别
public static void getVideoFromCamera() {
    VideoCapture capture = new VideoCapture(0);
    Mat video = new Mat();
    while (i < 3) {
        capture.read(video);
        HighGui.imshow("实时人脸识别", getFace(video));
        if (HighGui.waitKey(100) == 27) {
            break;
        }
    }
    capture.release();
}

// 从本地视频文件中识别人脸
public static void getVideoFromFile() {
    VideoCapture capture = new VideoCapture(PATH_PREFIX + "yimi.mp4");
    Mat video = new Mat();
    while (capture.isOpened()) {
        capture.read(video);
        HighGui.imshow("本地视频识别人脸", getFace(video));
        if (HighGui.waitKey(100) == 27) {
            break;
        }
    }
    capture.release();
}

// 本地图片人脸识别
public static void face(String filename) {
    Mat image = Imgcodecs.imread(PATH_PREFIX + filename);
    MatOfRect face = new MatOfRect();
    faceDetector.detectMultiScale(image, face);
    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);
        Imgcodecs.imwrite(PATH_PREFIX + "face.png", image);
    }
    HighGui.imshow("人脸识别", image);
    HighGui.waitKey(0);
}

---整理转载,方便使用

posted @ 2025-06-11 19:26  Moonbeamsc  阅读(24)  评论(0)    收藏  举报
返回顶端