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

news2024/11/16 7:35:39
1. opencv概述

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

opencv官网:https://opencv.org/

2. 安装opencv
2.1 下载opencv

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

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

build :基于window构建

sources:开源,提供源码

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

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

3. 代码实现
3.1 pom.xml添加依赖

版本的依赖与下载的opencv版本一致

<dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>opencv</artifactId>
            <version>4.7.0-1.5.9</version>
        </dependency>
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操作系统
            // 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;
    }



}

上述代码加载.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);

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

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 从摄像头实时读取 * @return: void * @date: 2019年8月19日 17:20:13
     */
    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;
            }
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1084787.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea中父工程Project创建

1.file-->new-->Project 2.选择maven包和JavaSDK 3.填写项目名&#xff0c;选择文件目录&#xff0c;项目包等 4.配置maven tip&#xff1a;约定>配置>编码 5.设置项目编码 6.注解生效激活&#xff0c;便于项目中使用注解 7.Java编译版本选择8 8.File Type 过滤&a…

Java idea查看自定义注解的调用地方

Java idea查看自定义注解的调用地方

RunnerGo UI自动化测试功能使用体验

首先需要进入官网&#xff0c;RunnerGo支持开源&#xff0c;可以自行下载安装&#xff0c;也可以点击右上角体验企业版按钮快速体验 点击体验企业版进入工作台后可以点击页面上方的UI自动化 进入到测试页面 创建元素 我们可以在元素管理中创建我们测试时需要的元素 这里我们以…

【低代码表单设计器】:创造高效率的流程化办公!

当前&#xff0c;有不少用户朋友对低代码表单设计器挺感兴趣。其实&#xff0c;如果想要实现提质增效的办公效率&#xff0c;创造一个流程化办公&#xff0c;那么确实可以了解低代码技术平台。流辰信息作为服务商&#xff0c;拥有较强的自主研发能力&#xff0c;根据市场的变化…

CANoe-如何实现27服务解锁

27服务解锁的工作原理可以在文章《诊断27服务介绍》查看,这里简单介绍下流程: Tester向ECU发送27 01诊断请求请求种子seed,ECU收到该请求后随机生成一个seed,通过67 01诊断响应发送给Tester。Tester收到该诊断响应后取出seed值,传入和ECU相同的算法后生成一个密钥keyT。然…

[C++11]花括号{}、initializer_list、auto、decltype

文章目录 1.花括号{ }的扩展2.initializer_list3.auto4.decltype5.容器的增加5.1array[useless]5.2forward_list[useless]5.3unordered_map/unordered_set5.4统一增加 6.知乎文章 1.花括号{ }的扩展 int main() {//C98花括号{ }支持 1.数组 2.结构体struct Point{int _x;int _…

系统韧性研究(1)| 何谓「系统韧性」?

过去十年&#xff0c;系统韧性作为一个关键问题被广泛讨论&#xff0c;在数据中心和云计算方面尤甚&#xff0c;同时它对赛博物理系统也至关重要&#xff0c;尽管该术语在该领域不太常用。大伙都希望自己的系统具有韧性&#xff0c;但这到底意味着什么&#xff1f;韧性与其他质…

“AI大模型+电子签”,下一站在哪?

大模型所带来的数据分析、训练能力&#xff0c;将使得一些厂商的数据优势被逐渐放大&#xff0c;打造自身的差异化&#xff0c;打破电子签赛道同质竞争的局面。 作者|斗斗 编辑|皮爷 出品|产业家 AI大模型爆发以来&#xff0c;参与者众多。在电子签领域&#xff0c;这个…

前端代码重复度检测

在前端开发中&#xff0c;代码的重复度是一个常见的问题。重复的代码不仅增加了代码的维护成本&#xff0c;还可能导致程序的低效运行。为了解决这个问题&#xff0c;有许多工具和技术被用来检测和消除代码重复。其中一个被广泛使用的工具就是jscpd。 jscpd简介 jscpd是一款开…

格式转换 ▏Python 实现Word转HTML

将Word转换为HTML能将文档内容发布在网页上&#xff0c;这样&#xff0c;用户就可以通过浏览器直接查看或阅读文档而无需安装特定的软件。Word转HTML对于在线发布信息、创建在线文档库以及构建交互式网页应用程序都非常有用。以下是用Python将Word转换为HTML网页的攻略&#xf…

软件测试/测试开发丨校招推荐-中控技术股份有限公司岗位开放

软件测试工程师 岗位职责 1.参与软件项目需求分析&#xff0c;根据需求制定测试方案&#xff0c;设计测试用例&#xff0c;输出测试报告&#xff1b; 2.实施软件测试&#xff0c;对产品的接口、功能、性能等方面的测试负责&#xff1b; 3.针对项目中的问题进行跟踪分析和报…

从一个咖啡机提取一个嵌入式前端应用

学习一下除C或系统外的另一种嵌入式程序编写方法&#xff0c;JavaScript用于UI的设计与串口设备的控制 设备是基于SSD202芯片&#xff0c;dispinit初始化LCD&#xff0c;mplayer为程序需要用到视频播放程序&#xff0c;感觉开发效率会比较高及用户体现会比较好&#xff0c;毕竟…

新书免费领 | 数睿数据参编的《零基础学低(无)代码》图书正式发行

由中国工业出版集团、电子工业出版社出版的《零基础学低&#xff08;无&#xff09;代码》图书现已正式对外发行&#xff0c;目前已在多个购书平台和阅读平台上线。 本书由中国软件行业协会应用软件产品云服务分会秘书长曹开彬、清华大学软件学院副研究员刘英博主编。数睿数据…

智能工厂:APS高级计划排程系统成为了制造业建设智能工厂的核心必要需求

近年来&#xff0c;中国经济受到了许多因素的影响&#xff0c;例如新冠疫情冲击和国内外经济环境的巨大变化&#xff0c;随着我国人口红利的减少和人力成本逐步的增加&#xff0c;不论是中大型或小微制造企业为了提高市场竞争力并降低生产成本&#xff0c;都纷纷开始规划建设数…

实用!生产车间管理方案(万人收藏)

生产车间怎么管理&#xff1f; 发现大多数是车间管理普遍存在的问题&#xff0c;本文总结了以下几个方面&#xff1a; 1、制度管理 &#xff08;1&#xff09;没有明确的生产计划&#xff0c;生产流程混乱 &#xff08;2&#xff09;没有准确的记录和跟踪 2、人员管理&…

MySQL分页排序注意事项

最近测试发现个bug&#xff0c;同一个列表&#xff0c;分页选择展示10条数据时和展示20条数据时&#xff0c;展示20条数据不是展示10条数据下10条数据&#xff0c;数据有所错乱&#xff0c;如下图示。 SELECTid,no,year,quarter,dept_id,dept_name,create_time FROMlist_list …

Blender:制作一个变形动画

就是一个球逐渐地变为一个立方体 首先创建一个球和一个立方体 然后把两个物体放在一起&#xff0c;放缩球&#xff0c;让球包含立方体 之后选中球&#xff0c;为其添加修改器&#xff0c;缩裹 在这里选择缩裹对象为立方体 然后在应用下拉箭头中选择“应用为形态键” 下一步选中…

文件混淆-界面介绍

​ 介绍文件混淆界面功能选项和操作流程 文件混淆-界面介绍 文件混淆功能区域包括3个功能区&#xff1a;顶部显示过滤区、中间文件列表区、底部的是否混淆开关 ​ 顶部介绍 显示控制区域&#xff0c;这个区域用来辅助显示过滤查看文件&#xff0c;不会修改文件显示方式&am…

vue3学习源码笔记(小白入门系列)------provide和 inject 跨层级数据传递原理

目录 前言provideinject 总结 前言 需要从父组件向子组件传递数据时&#xff0c;会使用 props。对于层级不深的父子组件可以通过 props 透传数据&#xff0c;但是当父子层级过深时&#xff0c;数据透传将会变得非常麻烦和难以维护。 而依赖注入则是为了解决 prop 逐级透传 的问…

python 将字节字符串转换成十六进制字符串

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 想将一个十六进制字符串解码成一个字节字符串或者将一个字节字符串编码成一个十六进制字符串 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、…