springboot集成opencv实现人脸识别功能的详细步骤

作者:御剑长歌 时间:2023-10-07 00:38:22 

前言

项目中检测人脸图片是否合法的功能,之前用的是百度的人脸识别接口,由于成本高昂不得不寻求替代方案。

什么是opencv?

OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Java、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

项目集成步骤

由于项目是放在Linux系统中跑的,开发环境是Windows10,所以项目中涉及到opencv的要分两套。

准备工作

 Windows安装opencv

opencv官网下载安装包https://opencv.org/releases/

springboot集成opencv实现人脸识别功能的详细步骤

我这里选择的是4.1.1版本
分别下载了Windows版本和源码

springboot集成opencv实现人脸识别功能的详细步骤

Windows环境下集成

安装opencv,没什么说的,指定一个路径安装即可,注意安装路径不能是中文。
项目中集成的三个关键点

  • 引入jar依赖

  • 读取OpenCV自带的人脸识别特征XML文件

  • 配置opencv的库文件地址

关键点1:引入jar包

jar包位置在安装路径下的java文件夹中

springboot集成opencv实现人脸识别功能的详细步骤

两种方式引入

方式一:idea添加jar

springboot集成opencv实现人脸识别功能的详细步骤

或者直接在Libraries中添加二者皆可。

方式二:将jar上传至 * ,在maven中引入

我这里是将jar上传至 * ,然后引用的。
注意Windows版的jar和Linux中的jar不一样,二者要区分开来
通过Maven配置在不同环境下加载不同的jar


<profiles>
   <profile>
       <id>dev</id>
       <dependencies>
<!--            本地引用-->
<!--                <dependency>-->
<!--                    <groupId>op</groupId>-->
<!--                    <artifactId>opencv</artifactId>-->
<!--                    <version>411</version>-->
<!--                    <scope>system</scope>-->
<!--                    <systemPath>-->
<!--                        ${project.basedir}/src/main/resources/opencv/windows/opencv-411.jar-->
<!--                    </systemPath>-->
<!--                </dependency>-->

<!--            仓库引用-->
           <dependency>
           <!--                这里改成自己的仓库地址-->
               <groupId>com.***.cloud.resource</groupId>
               <artifactId>opencv-window</artifactId>
               <version>411</version>
           </dependency>
       </dependencies>
       <activation>
           <activeByDefault>true</activeByDefault>
       </activation>
   </profile>
   <profile>
       <id>test</id>
       <dependencies>
           <dependency>
           <!--                这里改成自己的仓库地址-->
               <groupId>com.***.cloud.resource</groupId>
               <artifactId>opencv-linux</artifactId>
               <version>411</version>
           </dependency>
       </dependencies>
   </profile>
</profiles>

关键点2:配置人脸识别特征XML文件的地址

在bootstrap.yml添加如下参数


#  函数库地址 在 vm optionis中 配置
#  windows地址: -Djava.library.path=D:\software\opencv\build\java\x64
#  linux地址:   -Djava.library.path=/usr/local/opencv-4.1.1/build/lib/
opencv:
 lib:
   linuxxmlpath: /usr/local/share/opencv4/haarcascades/haarcascade_frontalface_alt.xml
   windowxmlpath: D:\software\opencv\sources\data\haarcascades\haarcascade_frontalface_alt.xml

测试的方法中就直接写死了


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

static {
       String systemProperties = String.valueOf(System.getProperties());
       log.info(systemProperties);
       System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
       faceDetector = new CascadeClassifier("D:\\software\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
   }

注意路径!!

关键点3:配置opencv的库文件地址

springboot集成opencv实现人脸识别功能的详细步骤


-Djava.library.path=D:\software\opencv\build\java\x64

这里其实指向的就是 该目录下的 opencv_java411.dll 文件
(linux的配置见下文)

代码

测试方法


package com.example.opencvdemo.test;

import lombok.extern.slf4j.Slf4j;
import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

/**
* @author aaron
* @since 2021-06-07
*/
@Slf4j
public class FaceVideo {
   /**
    * 初始化人脸探测器
    */
   static CascadeClassifier faceDetector;

static {
       String systemProperties = String.valueOf(System.getProperties());
       log.info(systemProperties);
       System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
       faceDetector = new CascadeClassifier("D:\\software\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml");
   }

public static void main(String[] args){
       // 3- 本地图片人脸识别,识别成功并保存人脸图片到本地
       String imgPath = "C:\\Users\\Administrator\\Pictures\\wang.jpg";
       face(imgPath);
   }

/**
    * OpenCV-4.1.1 图片人脸识别
    *
    * @return: void
    * @date: 2019年5月7日12:16:55
    */
   public static void face(String imgPath) {
       /**
        * 读取本地
        */
       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, "D:\\pictures\\" + 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));

}
}

注意!Mat image = Imgcodecs.imread(imgPath);
imgPath中不能带有中文!
opencv安装路径中如果有中文的话就会报错。

集成到Springboot


package com.example.opencvdemo.util;

import com.example.opencvdemo.exception.PublicException;
import com.example.opencvdemo.result.ErrorCode;
import com.google.common.primitives.Bytes;
import lombok.extern.slf4j.Slf4j;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

/**
* @author aaron
* @since 2021-06-07
*/
@Component
@Slf4j
public class OpenCvUtils implements CommandLineRunner {

@Value("${opencv.lib.linuxxmlpath}")
   private String linuxXmlPath;
   @Value("${opencv.lib.windowxmlpath}")
   private String windowXmlPath;

/**
    * 人脸探测器对象
    */
   static CascadeClassifier faceDetector;

/**
    * 判断是否是Windows系统
    */
   private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");

/**
    * 监测图片是否合法,是否只有一张脸
    */
   public static void checkFace(String pictureUrl) throws Exception {
//        //将在线图片保存为本地图片
//        String imgPath = saveLocal(pictureUrl);
//        //本地图片
//        File file  = new File(imgPath);
//        FileInputStream fileInputStream = new FileInputStream(file);
//        ByteArrayOutputStream out = new ByteArrayOutputStream();
//        byte[] localBuff = new byte[fileInputStream.available()];
//        fileInputStream.read(localBuff);
//        out.write(localBuff);
//        log.info("本地图片:"+localBuff.length);

//在线图片
       URL url = new URL(pictureUrl);
       URLConnection uc = url.openConnection();
       InputStream inputStream = uc.getInputStream();
       ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
       byte[] buff = new byte[1024];
       int rc;
       while ((rc = inputStream.read(buff, 0, 1024)) > 0) {
           swapStream.write(buff, 0, rc);
       }
       byte[] urlBuff = swapStream.toByteArray();

log.info("在线图片:"+urlBuff.length);

List<Byte> bs = new ArrayList<>();
       bs.addAll(Bytes.asList(urlBuff));
       log.info("buffer长度"+bs.size());
       /**
        * 不好使
        */
//        Mat image =  Converters.vector_char_to_Mat(bs);
//        Mat image  =  Converters.vector_uchar_to_Mat(bs);
       /**
        * 读取本地
        */
//        Mat image = Imgcodecs.imread(imgPath);
       /**
        * 读数据流
        */
       Mat image  = Imgcodecs.imdecode(new MatOfByte(urlBuff), Imgcodecs.IMREAD_UNCHANGED);

if (image.empty()) {
           log.error("image 内容不存在!");
           return;
       }
       // 3 特征匹配
       MatOfRect face = new MatOfRect();
       faceDetector.detectMultiScale(image, face);
       // 4 匹配 Rect 矩阵 数组
       Rect[] rects = face.toArray();
       System.out.println("匹配到 " + rects.length + " 个人脸");
//        delFile(imgPath);
       if (rects.length == 0) {
           throw new PublicException(ErrorCode.A0430.getCode(), "没有监测到人脸");
       } else if (rects.length > 1) {
           throw new PublicException(ErrorCode.A0430.getCode(), "检测到图片有多张人脸,请重新上传");
       }
   }

public static String saveLocal(String pictureUrl) throws IOException {
       URL url = new URL(pictureUrl);
       URLConnection uc = url.openConnection();
       InputStream inputStream = uc.getInputStream();
       String[] value = pictureUrl.split("/");
       String firstFilePath = "D:\\pictures\\";
       if (!IS_WINDOWS) {
           firstFilePath = "/tmp/tmp-picture/";
       }
       String fileName = firstFilePath + value[value.length - 1];
       FileOutputStream out = new FileOutputStream(fileName);
       int j = 0;
       while ((j = inputStream.read()) != -1) {
           out.write(j);
       }
       inputStream.close();
       return fileName;
   }

/**
    * Callback used to run the bean.
    *
    * @param args incoming main method arguments
    * @throws Exception on error
    */
   @Override
   public void run(String... args){
       String systemProperties = String.valueOf(System.getProperties());
       log.info(systemProperties);
       System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
       String path = "";
       //如果是window系统取出路径开头的/
       if (IS_WINDOWS) {
           path = windowXmlPath;
       }else{
           path = linuxXmlPath;
       }
       /**
        * 初始化人脸探测器
        */
       faceDetector = new CascadeClassifier(path);
       log.info("==========初始化人脸探测器成功===========");
   }
}

OpenCV 提供的 API 是直接根据路径读取图片的,所以最开始的时候我是把图片保存到本地在读取才成功的,但是这种方式太憨了点,在实际生产环境中,大部分情况下都是直接读取网络图片。在内存就完成图片和 opencv 的 Mat 对象的转换。这里代码中已经解决了url地址图片转化的问题。
这里附上解决该问题的博客 传送门

Linux安装opencv

Linux平台须要咱们手动编译,下载opencv-4.1.1.zip,解压到/user/local目录下,而后编译


yum  install   ant    gcc  gtk2-devel   pkgconfig  zlib-devel

安装unzip命令


yum install -y unzip zip

解压命令


unzip opencv-4.1.1.zip

yum   groupinstall "Development Tools"

安装cmake

查看cmake当前版本


cmake --version

yum -y install wget

下载获得cmake-3.9.2源码


wget https://cmake.org/files/v3.9/cmake-3.9.2.tar.gz

解压、安装新版本


tar -xvf cmake-3.9.2.tar.gz

cd cmake-3.9.2

./configure

sudo make && make install

cd /usr/local/opencv-4.1.1
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTS=OFF ..
make -j8
sudo make install

对应的jar和.so文件在


/usr/local/share/java/opencv4/

springboot集成opencv实现人脸识别功能的详细步骤

人脸识别特征XML文件的地址


/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_alt.xml

Linux启动

jar 启动命令添加Vm options


nohup java -jar -Djava.library.path=/usr/local/opencv-4.1.1/build/lib/ opencv-demo-1.0.jar  > logs/opencv-demo-1.0.log 2>&1 &

github直接白嫖

项目代码已上传至github,可通过web接口测试,也可用main方法测试。传送门

参考博客地址
https://blog.csdn.net/fangchao2011/article/details/99858927
https://blog.csdn.net/eggtargaryen/article/details/83343358
https://blog.csdn.net/wangyulj/article/details/79058390
https://blog.csdn.net/qq_25775675/article/details/107808544?
https://lequ7.com/guan-yu-springbootspringboot-shi-yong-opencv-zong-jie.htmlutm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242
https://blog.csdn.net/whudee/article/details/93379780

来源:https://blog.csdn.net/weixin_40392053/article/details/117748043

标签:springboot,opencv,人脸识别
0
投稿

猜你喜欢

  • C#实现过滤sql特殊字符的方法集合

    2022-01-30 23:58:04
  • SpringBoot 使用Prometheus采集自定义指标数据的方案

    2023-04-25 02:50:39
  • idea热部署插件jrebel正式版及破解版安装详细图文教程

    2023-05-27 03:28:59
  • Spring创建bean对象三种方式代码实例

    2023-02-04 08:53:33
  • android studio 3.6 中配置svn的教程

    2022-02-26 20:59:06
  • Android中自定义进度条详解

    2022-11-10 00:27:52
  • 解决grails服务端口冲突的办法(grails修改端口号)

    2023-09-12 01:00:03
  • MyBatis中map的应用与模糊查询实现代码

    2021-09-02 18:27:14
  • java实现的简单猜数字游戏代码

    2023-06-17 22:56:22
  • unity制作瞄准镜效果

    2022-04-15 23:45:10
  • SpringBoot集成kaptcha验证码

    2023-06-26 03:56:17
  • springboot中的pom文件 project报错问题

    2022-01-24 00:41:55
  • java编译时出现使用了未经检查或不安全的操作解决方法

    2022-05-21 00:21:21
  • 解决IDEA springboot"spring-boot-maven-plugin"报红问题

    2023-08-15 21:29:19
  • 详解OpenCV For Java环境搭建与功能演示

    2023-05-27 09:13:50
  • linux系统 java环境变量的配置方法

    2022-12-10 09:34:11
  • C#中分部类和分部方法的应用

    2022-08-16 06:49:05
  • flutter Container容器实现圆角边框

    2021-06-17 23:16:23
  • Android项目实战手把手教你画圆形水波纹loadingview

    2023-03-15 10:13:47
  • 浅谈Java安全之C3P0的使用

    2022-06-06 00:22:11
  • asp之家 软件编程 m.aspxhome.com