SpringBoot 集成 OpenCV 实现人脸检测功能

1 摘要

OpenCV 作为一个世界上最大的计算机视觉库,里边包含了非常丰富的函数,开箱即用。不过 OpenCV 都是以应用程序直接运行的方式在计算机上运行,要想通过各种编程语言来操作,就需要开发者自行适配。本文将介绍基于 Java 语言 SpringBoot 框架集成 OpenCV 实现图片人脸检测功能。

OpenCV 官网: https://opencv.org

市面上集成 OpenCV 的 java 库有不少,这里推荐两个用户比较多的:

JavaCV: https://github.com/bytedeco/javacv

JavaCV 是一个综合的 Java 库,提供统一的操作方法,除了集成了 OpenCV 之外还包括 FFmpeg 等众多出名的算法库。

OpenPnP: https://github.com/openpnp/opencv

OpenPnP-OpenCV 是由 OpenPnP 组织提供的 OpenCV 的 Java 适配版本,这个是只有 OpenCV 的接口,依赖体积小。

本文使用 OpenPnP 提供的 Java 库。

2 核心 Maven 依赖

demo-opencv/pom.xml
        <!--  openCV 函数库 -->
        <dependency>
            <groupId>org.openpnp</groupId>
            <artifactId>opencv</artifactId>
            <version>${openpnp-opencv.version}</version>
        </dependency>

其中 openpnp-opencv 的版本为:

<openpnp-opencv.version>4.9.0-0</openpnp-opencv.version>

这里 OpenPnP 的版本与 openCV 官方的版本保持了一致。

3 核心代码

3.1 人脸特征值匹配文件

人脸特征值匹配文件:

demo-opencv/src/main/resources/opencv/haarcascade_frontalface_alt.xml

这个文件比较大,这里就不展示代码了,需要的直接到 OpenCV 官方下载。

OpenCV 官方人脸特征值文件: https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_alt.xml

3.2 人脸检测工具类

demo-opencv/src/main/java/com/ljq/demo/springboot/opencv/common/util/FaceDetectUtil.java
package com.ljq.demo.springboot.opencv.common.util;


import lombok.extern.slf4j.Slf4j;
import nu.pattern.OpenCV;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.util.Objects;

/**
 * @Description: 人脸检测工具
 * @Author: junqiang.lu
 * @Date: 2024/3/15
 */
@Slf4j
public class FaceDetectUtil {

    private static  CascadeClassifier faceDetector;


    /**
     * 初始化 opencv
     *
     * @param isDebug
     * @return
     */
    public static CascadeClassifier init(boolean isDebug) {
        if (Objects.isNull(faceDetector) || faceDetector.empty()) {
            synchronized (FaceDetectUtil.class) {
                if (Objects.isNull(faceDetector) || faceDetector.empty()) {
                    try {
                        // 加载 openCV 函数库
                        OpenCV.loadShared();
                        log.info("opencv 函数库加载成功");
                        // 初始化人脸探测器
                        faceDetector = new CascadeClassifier();
                        String xmlFilePath =  "opencv" + File.separator + "haarcascade_frontalface_alt.xml";
                        boolean detectorInitResult = false;
                        if (isDebug) {
                            File xmlFile = ResourceUtils.getFile("classpath:" + xmlFilePath);
                            detectorInitResult = faceDetector.load(xmlFile.getAbsolutePath());
                        } else {
                            detectorInitResult = faceDetector.load(System.getProperty("user.dir") + File.separator + xmlFilePath);
                        }
                        log.info("opencv 人脸检测工具加载结果: {}", detectorInitResult);
                    } catch (Exception e) {
                        log.error("opencv face check init error", e);
                    }
                }
            }
        }
        return faceDetector;
    }


    /**
     * 检测本地照片中是否包含人脸
     *
     * @param imgPath
     * @param isDebug
     * @return
     */
    public static boolean detectFace(String imgPath, boolean isDebug) {
        init(isDebug);
        // 读取图片
        Mat image = Imgcodecs.imread(imgPath);
        return detectFace(image, isDebug);
    }

    /**
     * 检测照片中是否包含人脸
     *
     * @param byteArray
     * @param isDebug
     * @return
     */
    public static boolean detectFace(byte[] byteArray, boolean isDebug) {
        init(isDebug);
        // 读取图片
        Mat image = Imgcodecs.imdecode(new MatOfByte(byteArray), Imgcodecs.IMREAD_UNCHANGED);
        return detectFace(image, isDebug);
    }

    /**
     * 检测照片中是否包含人脸
     *
     * @param image
     * @param isDebug
     * @return
     */
    public static boolean detectFace(Mat image, boolean isDebug) {
        // 读取图片
        if (image.empty()) {
            return false;
        }
        // 人脸特征值匹配
        MatOfRect face = new MatOfRect();
        init(isDebug).detectMultiScale(image, face);
        // 特征匹配
        Rect[] rects = face.toArray();
        if (rects.length > 0) {
            return true;
        }
        return false;
    }




}

这里提供了三种图片人脸检测的方式,分别是本地文件,图片字节数组,以及 opencv 的 org.opencv.core.Mat 对象。

3.3 人脸检测 Controller

根据真实业务场景,用户上传图片,然后进行人脸检测。

demo-opencv/src/main/java/com/ljq/demo/springboot/opencv/controller/FaceDetectController.java
package com.ljq.demo.springboot.opencv.controller;

import com.ljq.demo.springboot.opencv.common.config.OpencvConfig;
import com.ljq.demo.springboot.opencv.common.util.FaceDetectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;

/**
 * @Description: 人脸检测控制层
 * @Author: junqiang.lu
 * @Date: 2024/3/18
 */
@Slf4j
@RequestMapping(value = "/api/opencv")
@RestController
public class FaceDetectController {

    @Resource
    private OpencvConfig opencvConfig;

    /**
     * 人脸检测
     *
     * @param file
     * @return
     */
    @PostMapping(value = "/face/detect", produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<Object> detectFace(MultipartFile file){
        boolean flag = false;
        try {
            flag = FaceDetectUtil.detectFace(file.getBytes(), opencvConfig.getOpencvDebug());
            log.info("图片人脸检测结果: {}", flag);
        } catch (IOException e) {
            log.error("图片读取错误", e);
        }
        return ResponseEntity.ok(flag);
    }


}

3.4 其他相关代码

3.4.1 OpenCV 的配置类
demo-opencv/src/main/java/com/ljq/demo/springboot/opencv/common/config/OpencvConfig.java
package com.ljq.demo.springboot.opencv.common.config;

import lombok.Getter;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: opencv 配置
 * @Author: junqiang.lu
 * @Date: 2024/3/18
 */
@ToString
@Getter
@Configuration
public class OpencvConfig {

    /**
     * 是否开启 opencv 调试模式
     * true: 从项目resource文件中加载人脸特征xml,实际部署,以 jar 启动无法获取到
     * false: 从本地文件加载人脸特征xml
     */
    @Value("${opencv.debug:false}")
    private Boolean opencvDebug;


}
3.4.2 application 配置文件
demo-opencv/src/main/resources/application.yml
# config
server:
  port: 9211


# spring
spring:
  application:
    name: demo-opencv
  servlet:
    multipart:
      max-file-size: 1000MB
      max-request-size: 1000MB


# opencv properties
opencv:
  debug: true

4 注意事项

4.1 人脸特征值匹配文件

OpenCV 函数库读取配置文件是必须按照文件的绝对路径来读取的,对于在 jar 包内的配置文件,是无法读取到的。因此在实际项目的部署中必须将人脸特征匹配文件外置。这也是上边专门设置一个 opencv 配置类的原因。

4.2 OpenCV 依赖的 GLIBC 版本问题

OpenCV 4.9 依赖的 GLIBC 版本为 2.27,CentOS 7 系统自带的 GLIBC 版本为 2.17,如果不手动安装高版本 GLIBC,程序将无法在 CentOS 7 上边运行。Windows 7 系统也无法运行,Windows 10 系统可以。

如果要在 CentOS 7 系统上直接运行,可以选择依赖的版本为 3.4.2-2。

作为 CentOS 系统的平行替代, Alma Linux 9.3 系统自带的 GLIBC 版本为 2.34,可以直接支持 OpenCV 4.9 运行。

Linux 系统查看 GLIBC 版本命令:

ldd --version

Linux 系统查看系统支持的 GLIBC 版本列表:

strings  /lib64/libc.so.6 | grep GLIBC_

低版本 GLIBC 运行程序时抛出的异常如下:

2024-05-08 11:05:09 | ERROR | http-nio-9211-exec-1 | org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] 175 | Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: /tmp/opencv_openpnp7898379110605450114/nu/pattern/opencv/linux/x86_64/libopencv_java490.so: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /tmp/opencv_openpnp7898379110605450114/nu/pattern/opencv/linux/x86_64/libopencv_java490.so)] with root cause
java.lang.UnsatisfiedLinkError: /tmp/opencv_openpnp7898379110605450114/nu/pattern/opencv/linux/x86_64/libopencv_java490.so: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /tmp/opencv_openpnp7898379110605450114/nu/pattern/opencv/linux/x86_64/libopencv_java490.so)
        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at nu.pattern.OpenCV$SharedLoader.<init>(OpenCV.java:225)
        at nu.pattern.OpenCV$SharedLoader.<init>(OpenCV.java:189)
        at nu.pattern.OpenCV$SharedLoader$Holder.<clinit>(OpenCV.java:261)
        at nu.pattern.OpenCV$SharedLoader.getInstance(OpenCV.java:265)
        at nu.pattern.OpenCV.loadShared(OpenCV.java:183)
        at com.ljq.demo.springboot.opencv.common.util.FaceCheckUtil.init(FaceCheckUtil.java:40)
        at com.ljq.demo.springboot.opencv.common.util.FaceCheckUtil.checkFace(FaceCheckUtil.java:85)
        at com.ljq.demo.springboot.opencv.controller.FaceCheckController.checkFaceOpenpnp(FaceCheckController.java:39)

5 推荐参考资料

OpenPnP OpenCV Github

Intro to OpenCV with Java–Baeldung

Capturing Image From Webcam in Java – Baeldung

6 Github 源码

Gtihub 源码地址 : https://github.com/Flying9001/springBootDemo/tree/master/demo-opencv

个人公众号:404Code,分享半个互联网人的技术与思考,感兴趣的可以关注.
404Code

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了实现Spring Boot集成OpenCV实现人脸识别,需要按照以下步骤: 1. 安装OpenCV库:在本地计算机上安装OpenCV库,并确保可以在计算机上使用OpenCV命令行工具。 2. 创建Spring Boot应用程序:使用Spring Initializr创建一个新的Spring Boot项目。 3. 添加依赖项:在pom.xml文件中添加OpenCV依赖项。 4. 编写代码:编写Java代码来实现人脸识别功能。在代码中,需要使用OpenCV库提供的方法来加载图像、检测人脸等。 5. 测试应用程序:启动Spring Boot应用程序,并使用浏览器或其他工具测试人脸识别功能。 以下是一个示例代码,演示如何使用OpenCV库在Spring Boot应用程序中实现人脸识别功能。 ```java import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.objdetect.CascadeClassifier; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class FaceRecognitionController { @GetMapping("/detect-face") @ResponseBody public String detectFace(@RequestParam("imagePath") String imagePath) { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // Load image Mat image = Imgcodecs.imread(imagePath); // Load classifier CascadeClassifier faceDetector = new CascadeClassifier("haarcascade_frontalface_alt.xml"); // Detect faces MatOfRect faceDetections = new MatOfRect(); faceDetector.detectMultiScale(image, faceDetections); // Draw rectangles around detected faces for (Rect rect : faceDetections.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)); } // Save output image Imgcodecs.imwrite("output.jpg", image); return "Face detection completed"; } } ``` 在这个示例代码中,我们使用了OpenCV库的以下功能: - 加载图像:使用Imgcodecs.imread()方法加载图像。 - 加载分类器:使用CascadeClassifier类加载分类器。 - 检测人脸:使用CascadeClassifier.detectMultiScale()方法检测人脸。 - 绘制矩形:使用Imgproc.rectangle()方法在检测到的人脸周围绘制矩形。 - 保存图像:使用Imgcodecs.imwrite()方法将输出图像保存到本地文件。 最后,我们将上述代码编译、打包为可执行的jar包,并在命令行中启动Spring Boot应用程序。启动成功后,可以使用浏览器或其他工具通过HTTP请求来测试人脸识别功能。例如,可以使用以下命令来检测一张名为“test.jpg”的人脸图像: ``` curl http://localhost:8080/detect-face?imagePath=/path/to/test.jpg ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值