springboot集成opencv实现人脸识别功能的详细步骤
前言
项目中检测人脸图片是否合法的功能,之前用的是百度的人脸识别接口,由于成本高昂不得不寻求替代方案。
什么是opencv?
OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Java、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
项目集成步骤
由于项目是放在Linux系统中跑的,开发环境是Windows10,所以项目中涉及到opencv的要分两套。
准备工作
Windows安装opencv
opencv官网下载安装包https://opencv.org/releases/
我这里选择的是4.1.1版本
分别下载了Windows版本和源码
Windows环境下集成
安装opencv,没什么说的,指定一个路径安装即可,注意安装路径不能是中文。
项目中集成的三个关键点。
- 引入jar依赖
- 读取OpenCV自带的人脸识别特征XML文件
- 配置opencv的库文件地址
关键点1:引入jar包
jar包位置在安装路径下的java文件夹中
两种方式引入
方式一:idea添加jar
或者直接在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的库文件地址
-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/
人脸识别特征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
以上就是springboot集成opencv实现人脸识别功能的详细内容,更多关于springboot opencv人脸识别的资料请关注猪先飞其它相关文章!
相关文章
- 这篇文章主要介绍了python-opencv-画外接矩形框的实例代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-04
解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题
这篇文章主要介绍了解决springboot使用logback日志出现LOG_PATH_IS_UNDEFINED文件夹的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-28- 这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
- 这篇文章主要介绍了详解springBoot启动时找不到或无法加载主类解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
- 这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
- 图片剪裁是常用的方法,那么如何通过4坐标剪裁图片,本文就详细的来介绍一下,感兴趣的小伙伴们可以参考一下...2021-06-04
- 这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
Spring Boot项目@RestController使用重定向redirect方式
这篇文章主要介绍了Spring Boot项目@RestController使用重定向redirect方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-02- 这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10
- 这篇文章主要介绍了Springboot+TCP监听服务器搭建过程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-28
- 这篇文章主要介绍了OpenCV如何去除图片中的阴影的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-29
- 这篇文章主要介绍了解决使用OpenCV中的imread()内存报错问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
- 这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
- 这篇文章主要介绍了使用OpenCV去除面积较小的连通域,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-05
详解SpringBoot之访问静态资源(webapp...)
这篇文章主要介绍了详解SpringBoot之访问静态资源(webapp...),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-14springboot中使用@Transactional注解事物不生效的坑
这篇文章主要介绍了springboot中使用@Transactional注解事物不生效的原因,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26详解pycharm的python包opencv(cv2)无代码提示问题的解决
这篇文章主要介绍了详解pycharm的python包opencv(cv2)无代码提示问题的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-29- 这篇文章主要介绍了springboot多模块包扫描问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-16
在C#中使用OpenCV(使用OpenCVSharp)的实现
这篇文章主要介绍了在C#中使用OpenCV(使用OpenCVSharp)的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-15- 这篇文章主要介绍了Springboot实现多线程注入bean的工具类操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-27