当前位置:   article > 正文

Java使用opencv实现人脸识别、人脸比对_java 人脸识别

java 人脸识别
1. opencv概述

OpenCV是一个开源的计算机视觉库,它提供了一系列丰富的图像处理和计算机视觉算法,包括图像读取、显示、滤波、特征检测、目标跟踪等功能。

opencv官网:https://opencv.org/
opencv官网文档:https://docs.opencv.org/4.7.0/index.html
参考教程1:https://www.w3cschool.cn/opencv/
参考教程2:https://www.yiibai.com/opencv/opencv_adding_text.html

2. 安装opencv
2.1 下载opencv

opencv下载:https://opencv.org/releases/
在这里插入图片描述
这里我们使用4.7.0版本,下载到本地后,双击进行安装即可。

进入到opencv的安装目录:
在这里插入图片描述

build :基于window构建

sources:开源,提供源码
  • 1
  • 2
  • 3

进入到build\java 目录
在这里插入图片描述

x64与x86目录下是对应的.dll文件:代表给不同的系统使用,下面的代码会使用到.dll文件
opencv-460.jar给java操作openvc的程序包

2.2 准备文件
# 1. 特征分类器:windows 和 linux 中的配置文件都一样,随便用哪个都行
haarcascade_frontalface_alt.xml
# windows 路径 : opencv\build\etc\haarcascades
# linux 路径 : /usr/local/share/opencv4/haarcascades

# 2. jar 包 - 也可以直接使用 javacv 中的 opencv 包
opencv-470.jar
# windows 路径 : {opencv安装目录}\opencv\build\java
# linux 路径 : /usr/local/share/java/opencv4

# 3. 动态库
opencv_java470.dll (windows系统使用此文件)
# windows 路径 : {opencv安装目录}\opencv\build\java\{x64}/{x86} 跟据系统选择
libopencv_java470.so (linux系统使用此文件)
# linux 路径 : /usr/local/share/java/opencv4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
3. 代码实现
3.1 pom.xml添加依赖
<!-- 版本的依赖与下载的opencv版本一致-->
<dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>opencv</artifactId>
            <version>4.7.0-1.5.9</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

或:

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.9</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

或:

<dependency>
            <groupId>org.openpnp</groupId>
            <artifactId>opencv</artifactId>
            <version>4.7.0-0</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

以上三个依赖任选其一即可,项目打包后观察一下使用哪个依赖打包后的jar文件更小

实验证明:
javacv-platform依赖的jar最大,达到929.64M
org.openpnp.opencv依赖最小,几乎为0M
org.bytedeco.opencv依赖居中,大小为2M

ps:依赖包太大,优化参考:https://blog.csdn.net/u014644574/article/details/122067708

3.2 编写代码

ps:代码中存在加载.dll、haarcascade_frontalface_alt.xml文件,请确保文件地址正确

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操作系统
            // todo windows 系统部署加载 .dll 文件 - 路径跟据自己存放位置更改【这里需要使用绝对路径】
            System.load("D:\\opencv\\opencv\\build\\java\\x64\\opencv_java470.dll");
        } else if (os != null && os.toLowerCase().startsWith("linux")) {
            // Linux操作系统
            // todo Linux 服务器部署加载 .so 文件 - 路径跟据自己存放位置更改【是否需要绝对路径有待验证,目前只在windows 系统实践过】
            System.load("/opt/face/libopencv_java440.so");
        }

        // 引入 特征分类器配置 文件:haarcascade_frontalface_alt.xml 文件路径
        // 此文件在opencv的安装目录build\etc\haarcascades下可以找到
        String property = "D:\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml";
        System.out.println(property);
        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);
        // rect中人脸图片的范围
        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(10000000);
        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);
        // CORREL 相关系数
        double res = Imgproc.compareHist(hist_1, hist_2, Imgproc.CV_COMP_CORREL);
        return res;
    }



}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

上述代码加载.dll文件也可使用以下方式:

ps:【不过以下方式需要将opencv安装目录下的build\java\x64\opencv_java470.dll文件复制到C:\Windows\System32目录下才可使用否则会报错】

// 使用此方法需将D:\opencv\opencv\build\java\x64\opencv_java470.dll文件复制到C:\Windows\System32目录下
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
  • 1
  • 2

如下:
在这里插入图片描述

4. 效果

在这里插入图片描述

5. 附:完整代码

包括:
从摄像头实时人脸识别,识别成功保存图片到本地
从本地视频文件中识别人脸
本地图片人脸识别,识别成功并保存人脸图片到本地

package com.testpro.test.opencv;

import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;
import org.opencv.videoio.Videoio;

import java.util.Arrays;

/**
 * Opencv 图片人脸识别、实时摄像头人脸识别、视频文件人脸识别
 */
public class FaceVideo {

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

    static int i = 0;

    static {
        // 判断系统
        String os = System.getProperty("os.name");

        // 加载动态库
        if (os != null && os.toLowerCase().startsWith("windows")) {
            // Windows操作系统
            // todo windows 系统部署加载 .dll 文件 - 路径跟据自己存放位置更改
            System.load("D:\\opencv\\opencv\\build\\java\\x64\\opencv_java470.dll");
//            ClassLoader.getSystemResource("dlls/opencv_java470.dll");
        } else if (os != null && os.toLowerCase().startsWith("linux")) {
            // Linux操作系统
            // todo Linux 服务器部署加载 .so 文件 - 路径跟据自己存放位置更改
            System.load("/opt/face/libopencv_java440.so");
        }

        // 引入 特征分类器配置 文件:haarcascade_frontalface_alt.xml 文件路径
        String property = "D:\\opencv\\opencv\\build\\etc\\haarcascades\\haarcascade_frontalface_alt.xml";
        System.out.println(property);
        faceDetector = new CascadeClassifier(property);
    }

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

    public static void main(String[] args) {
        // 1- 从摄像头实时人脸识别,识别成功保存图片到本地
//        getVideoFromCamera();

        // 2- 从本地视频文件中识别人脸
//        getVideoFromFile();

        // 3- 本地图片人脸识别,识别成功并保存人脸图片到本地
//        face("5-1.jpg");

        // 4- 比对本地2张图的人脸相似度 (越接近1越相似)
        double compareHist = compare_image(PATH_PREFIX + "5-1.jpg", PATH_PREFIX + "6-1.jpg");
        System.out.println(compareHist);
        if (compareHist > 0.72) {

            System.out.println("人脸匹配");
        } else {

            System.out.println("人脸不匹配");
        }
    }


    /**
     * OpenCV-4.7.0 从摄像头实时读取
     */
    public static void getVideoFromCamera() {
        //1 如果要从摄像头获取视频 则要在 VideoCapture 的构造方法写 0
        VideoCapture capture = new VideoCapture(0);
        Mat video = new Mat();
        int index = 0;
        if (capture.isOpened()) {

            while (i < 3) {
                // 匹配成功3次退出
                capture.read(video);
                HighGui.imshow("实时人脸识别", getFace(video));
                index = HighGui.waitKey(100);
                if (index == 27) {

                    capture.release();
                    break;
                }
            }
        } else {

            System.out.println("摄像头未开启");
        }
        try {

            capture.release();
            Thread.sleep(1000);
            System.exit(0);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
        return;
    }

    /**
     * OpenCV-4.7.0 从视频文件中读取
     */
    public static void getVideoFromFile() {

        VideoCapture capture = new VideoCapture();
        capture.open(PATH_PREFIX + "yimi.mp4");//1 读取视频文件的路径

        if (!capture.isOpened()) {

            System.out.println("读取视频文件失败!");
            return;
        }
        Mat video = new Mat();
        int index = 0;
        while (capture.isOpened()) {

            capture.read(video);//2 视频文件的视频写入 Mat video 中
            HighGui.imshow("本地视频识别人脸", getFace(video));//3 显示图像
            index = HighGui.waitKey(100);//4 获取键盘输入
            if (index == 27) {
                //5 如果是 Esc 则退出
                capture.release();
                return;
            }
        }
    }

    /**
     * OpenCV-4.7.0 人脸识别
     *
     * @param image 待处理Mat图片(视频中的某一帧)
     * @return 处理后的图片
     */
    public static Mat getFace(Mat image) {
        // 1 读取OpenCV自带的人脸识别特征XML文件(faceDetector)
//        CascadeClassifier facebook = new CascadeClassifier("D:\\Sofeware\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
        // 2 特征匹配类
        MatOfRect face = new MatOfRect();
        // 3 特征匹配
        faceDetector.detectMultiScale(image, face);
        Rect[] rects = face.toArray();
        System.out.println("匹配到 " + rects.length + " 个人脸");
        if (rects != null && rects.length >= 1) {

            // 4 为每张识别到的人脸画一个圈
            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, "Human", 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);
                //Mat dst=image.clone();
                //Imgproc.resize(image, image, new Size(300,300));
            }
            i++;
            if (i == 3) {
                // 获取匹配成功第10次的照片
                Imgcodecs.imwrite(PATH_PREFIX + "face.png", image);
            }
        }
        return image;
    }


    /**
     * OpenCV-4.7.0 图片人脸识别
     */
    public static void face(String filename) {
        // 1 读取OpenCV自带的人脸识别特征XML文件
        // OpenCV 图像识别库一般位于 opencv\sources\data 下面
//        CascadeClassifier facebook=new CascadeClassifier("D:\\Sofeware\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
        // 2 读取测试图片
        String imgPath = PATH_PREFIX + filename;
        Mat image = Imgcodecs.imread(imgPath);
        if (image.empty()) {

            System.out.println("image 内容不存在!");
            return;
        }
        // 3 特征匹配
        MatOfRect face = new MatOfRect();
        faceDetector.detectMultiScale(image, face);
        // 4 匹配 Rect 矩阵 数组
        Rect[] rects = face.toArray();
        System.out.println("匹配到 " + rects.length + " 个人脸");
        // 5 为每张识别到的人脸画一个圈
        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, PATH_PREFIX + i + ".jpg", rect.x, rect.y, rect.width, rect.height);// 进行图片裁剪
            i++;
        }
        // 6 展示图片
        HighGui.imshow("人脸识别", image);
        HighGui.waitKey(0);
    }

    /**
     * 裁剪人脸
     *
     * @param imagePath
     * @param outFile
     * @param posX
     * @param posY
     * @param width
     * @param height
     */
    public static void imageCut(String imagePath, String outFile, int posX, int posY, int width, int height) {
        // 原始图像
        Mat image = Imgcodecs.imread(imagePath);
        // 截取的区域:参数,坐标X,坐标Y,截图宽度,截图长度
        Rect rect = new Rect(posX, posY, width, height);
        // 两句效果一样
        Mat sub = image.submat(rect); // Mat sub = new Mat(image, rect);
        Mat mat = new Mat();
        Size size = new Size(width, height);
        Imgproc.resize(sub, mat, size);// 将人脸进行截图并保存
        Imgcodecs.imwrite(outFile, mat);
        System.out.println(String.format("图片裁切成功,裁切后图片文件为: %s", outFile));
    }

    /**
     * 人脸比对
     *
     * @param img_1
     * @param img_2
     * @return
     */
    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);

        // CORREL 相关系数
        double res = Imgproc.compareHist(hist_1, hist_2, Imgproc.CV_COMP_CORREL);
        return res;
    }

    /**
     * 灰度化人脸
     *
     * @param img
     * @return
     */
    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);
        // rect中人脸图片的范围
        for (Rect rect : faceDetections.toArray()) {

            Mat face = new Mat(image1, rect);
            return face;
        }
        return null;
    }

    /**
     * OpenCV-4.7.0 将摄像头拍摄的视频写入本地
     */
    public static void writeVideo() {

        //1 如果要从摄像头获取视频 则要在 VideoCapture 的构造方法写 0
        VideoCapture capture = new VideoCapture(0);
        Mat video = new Mat();
        int index = 0;
        Size size = new Size(capture.get(Videoio.CAP_PROP_FRAME_WIDTH), capture.get(Videoio.CAP_PROP_FRAME_HEIGHT));
        VideoWriter writer = new VideoWriter("D:/a.mp4", VideoWriter.fourcc('D', 'I', 'V', 'X'), 15.0, size, true);
        while (capture.isOpened()) {

            capture.read(video);//2 将摄像头的视频写入 Mat video 中
            writer.write(video);
            HighGui.imshow("像头获取视频", video);//3 显示图像
            index = HighGui.waitKey(100);//4 获取键盘输入
            if (index == 27) {
                //5 如果是 Esc 则退出
                capture.release();
                writer.release();
                return;
            }
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/105385
推荐阅读
相关标签
  

闽ICP备14008679号