前言
最近公司项目有个新需求,需要对小程序拍摄的照片进行人脸识别,并且将人脸部分截取保存到服务器,用于人脸结果分析,网上查了很多资料,敲定了使用opencv做人脸识别,项目是spring boot,下面会具体细说
一、OpenCV简介
OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 它轻量级而且高效–由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
二、安装opencv
这个是opencv的中文文档
1.下载opencv
这里我是在windows安装的(我安装的是4.5.1版本):
参考地址:https://blog.csdn.net/LEON1741/article/details/90211061
2.配置
Eclipse
配置:
参考地址:https://blog.csdn.net/qq_37598011/article/details/86521560
idea
配置(我使用的idea)
1、下载完成后解压:
2、拷贝jar包和haarcascade_frontalface_alt.xml文件拷贝到项目resources目录下
3、修改pom文件
<dependency>
<groupId>org.opencv</groupId>
<artifactId>opencv</artifactId>
<version>4.5.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/opencv-451.jar</systemPath>
</dependency>
4、编辑springboot类的VM配置,指定opencv_java451.dll文件所在的目录
-Djava.library.path=dll文件所在目录
三、测试
1.代码
@PostMapping("/upload")
public void FaceDetector(HttpServletResponse response, MultipartFile multipartFile) throws IOException {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.out.println("人脸检测开始……");
//对图片进行降采样
InputStream inputStream = multipartFile.getInputStream();
File tofile = IOUtil.mult2File(multipartFile);
BufferedImage bufImg = ImageIO.read(inputStream);
inputStream.close();
int w = bufImg.getWidth();
int h = bufImg.getHeight();
if (bufImg.getWidth()>1000||bufImg.getHeight()>1000){
w=bufImg.getWidth()/2;
h=bufImg.getHeight()/2;
}
Thumbnails.of(multipartFile.getInputStream()).size(w, h).toFile(tofile);
//图片到这就已经压缩好了,后面我全是为了上传到oss上做准备工作
InputStream inputStreams = new FileInputStream(tofile);
MultipartFile file = new MockMultipartFile(tofile.getName(), inputStreams);
// 创建临时文件,因为boot打包后无法读取文件内的内容
File targetXmlFile = new File("src/" + xml.getFilename() + "");
FileUtils.copyInputStreamToFile(xml.getInputStream(), targetXmlFile);
CascadeClassifier faceDetector = new CascadeClassifier(targetXmlFile.toString());
if (faceDetector.empty()) {
System.out.println("请引入文件……");
return;
}
// 创建图片tempFile
File tempFile = new File("src/" + "121.jpg" + "");
FileUtils.copyInputStreamToFile(file.getInputStream(), tempFile);
// 读取创建的图片tempFile
Mat image = Imgcodecs.imread(tempFile.toString());
MatOfRect faceDetections = new MatOfRect();
// 进行人脸检测
faceDetector.detectMultiScale(image, faceDetections);
System.out.println(String.format("检测到人脸: %s", faceDetections.toArray().length));
Integer i = 1;
// 将图填充到image中
for (Rect rect : faceDetections.toArray()) {
Imgproc.rectangle(image, new Point((rect.x-10), (rect.y-60)), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0), 4);
imageCut(tempFile.toString(), i+".jpg", (rect.x-20), (rect.y-60), (rect.width + 30), (rect.height + 110));// 进行图片裁剪
i++;
}
// 下面部分是返回给页面
String filename = "111.jpg";
Imgcodecs.imwrite(filename, image);
File imgFile = new File(filename);
if (imgFile.exists()) {
response.getOutputStream().write(toByteArray(imgFile));
response.getOutputStream().close();
}
// 删除临时文件
if (targetXmlFile.exists() && targetXmlFile.isFile()) {
if (targetXmlFile.delete()) {
System.out.println("删除临时文件" + targetXmlFile + "成功!");
}
}
if (imgFile.exists() && imgFile.isFile()) {
if (imgFile.delete()) {
System.out.println("删除临时文件" + imgFile + "成功!");
}
}
if (tempFile.exists() && tempFile.isFile()) {
if (tempFile.delete()) {
System.out.println("删除临时文件" + tempFile + "成功!");
}
}
}
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 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));
}
public static byte[] toByteArray(File file) throws IOException {
File f = file;
if (!f.exists()) {
throw new FileNotFoundException("file not exists");
}
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(f));
int buf_size = 1024;
byte[] buffer = new byte[buf_size];
int len = 0;
while (-1 != (len = in.read(buffer, 0, buf_size))) {
bos.write(buffer, 0, len);
}
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
bos.close();
}
}
2.效果