springboot集成opencv實現(xiàn)人臉識別功能的詳細(xì)步驟
前言
項目中檢測人臉圖片是否合法的功能,之前用的是百度的人臉識別接口,由于成本高昂不得不尋求替代方案。
什么是opencv?
OpenCV是一個基于BSD許可(開源)發(fā)行的跨平臺計算機(jī)視覺和機(jī)器學(xué)習(xí)軟件庫,可以運行在Linux、Windows、Android和Mac OS操作系統(tǒng)上。輕量級而且高效——由一系列 C 函數(shù)和少量 C++ 類構(gòu)成,同時提供了Python、Java、MATLAB等語言的接口,實現(xiàn)了圖像處理和計算機(jī)視覺方面的很多通用算法。
項目集成步驟
由于項目是放在Linux系統(tǒng)中跑的,開發(fā)環(huán)境是Windows10,所以項目中涉及到opencv的要分兩套。
準(zhǔn)備工作
Windows安裝opencv
opencv官網(wǎng)下載安裝包https://opencv.org/releases/

我這里選擇的是4.1.1版本
分別下載了Windows版本和源碼

Windows環(huán)境下集成
安裝opencv,沒什么說的,指定一個路徑安裝即可,注意安裝路徑不能是中文。
項目中集成的三個關(guān)鍵點。
- 引入jar依賴
- 讀取OpenCV自帶的人臉識別特征XML文件
- 配置opencv的庫文件地址
關(guān)鍵點1:引入jar包
jar包位置在安裝路徑下的java文件夾中

兩種方式引入
方式一:idea添加jar

或者直接在Libraries中添加二者皆可。
方式二:將jar上傳至私服,在maven中引入
我這里是將jar上傳至私服,然后引用的。
注意Windows版的jar和Linux中的jar不一樣,二者要區(qū)分開來
通過Maven配置在不同環(huán)境下加載不同的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>
關(guān)鍵點2:配置人臉識別特征XML文件的地址
在bootstrap.yml添加如下參數(shù)
# 函數(shù)庫地址 在 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");
}
注意路徑!!
關(guān)鍵點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 內(nèi)容不存在!");
return;
}
// 3 特征匹配
MatOfRect face = new MatOfRect();
faceDetector.detectMultiScale(image, face);
// 4 匹配 Rect 矩陣 數(shù)組
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);// 進(jìn)行圖片裁剪
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);
// 截取的區(qū)域:參數(shù),坐標(biāo)X,坐標(biāo)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);// 將人臉進(jìn)行截圖并保存
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系統(tǒng)
*/
private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
/**
* 監(jiān)測圖片是否合法,是否只有一張臉
*/
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);
/**
* 讀數(shù)據(jù)流
*/
Mat image = Imgcodecs.imdecode(new MatOfByte(urlBuff), Imgcodecs.IMREAD_UNCHANGED);
if (image.empty()) {
log.error("image 內(nèi)容不存在!");
return;
}
// 3 特征匹配
MatOfRect face = new MatOfRect();
faceDetector.detectMultiScale(image, face);
// 4 匹配 Rect 矩陣 數(shù)組
Rect[] rects = face.toArray();
System.out.println("匹配到 " + rects.length + " 個人臉");
// delFile(imgPath);
if (rects.length == 0) {
throw new PublicException(ErrorCode.A0430.getCode(), "沒有監(jiān)測到人臉");
} 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系統(tǒng)取出路徑開頭的/
if (IS_WINDOWS) {
path = windowXmlPath;
}else{
path = linuxXmlPath;
}
/**
* 初始化人臉探測器
*/
faceDetector = new CascadeClassifier(path);
log.info("==========初始化人臉探測器成功===========");
}
}
OpenCV 提供的 API 是直接根據(jù)路徑讀取圖片的,所以最開始的時候我是把圖片保存到本地在讀取才成功的,但是這種方式太憨了點,在實際生產(chǎn)環(huán)境中,大部分情況下都是直接讀取網(wǎng)絡(luò)圖片。在內(nèi)存就完成圖片和 opencv 的 Mat 對象的轉(zhuǎn)換。這里代碼中已經(jīng)解決了url地址圖片轉(zhuǎn)化的問題。
這里附上解決該問題的博客 傳送門
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當(dāng)前版本
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
對應(yīng)的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實現(xiàn)人臉識別功能的詳細(xì)內(nèi)容,更多關(guān)于springboot opencv人臉識別的資料請關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot集成WebSocket長連接實際應(yīng)用詳解
- SpringBoot集成WebSocket遇到的問題及解決
- 使用WebSocket+SpringBoot+Vue搭建簡易網(wǎng)頁聊天室的實現(xiàn)代碼
- SpringBoot整合WebSocket實現(xiàn)后端向前端發(fā)送消息的實例代碼
- SpringBoot集成百度AI實現(xiàn)人臉識別的項目實踐
- SpringBoot實現(xiàn)人臉識別等多種登錄方式
- 如何基于SpringBoot實現(xiàn)人臉識別功能
- Springboot實現(xiàn)人臉識別與WebSocket長連接的實現(xiàn)代碼
相關(guān)文章
實例解析Json反序列化之ObjectMapper(自定義實現(xiàn)反序列化方法)
這篇文章主要介紹了實例解析Json反序列化之ObjectMapper,json自定義序列化的方法,需要的朋友可以了解下。2017-09-09
Spring內(nèi)部bean和級聯(lián)屬性用法詳解
這篇文章主要介紹了Java內(nèi)部bean和級聯(lián)屬性用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
spring-cloud入門之eureka-client(服務(wù)注冊)
本篇文章主要介紹了spring-cloud入門之eureka-client(服務(wù)注冊),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01
spring boot springMVC擴(kuò)展配置實現(xiàn)解析
這篇文章主要介紹了spring boot springMVC擴(kuò)展配置實現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-08-08

