本文展示Windows下Spring Boot 整合Opencv 4.5 进行对图片中的人脸提取,开发工具IDEA。
1、下载opencv安装包【下载地址】

2、下载后运行exe、安装。

1、创建空白spring boot项目,jar放入如下图,pom添加依赖。

4.0.0 org.example OpenCVStudy 1.0-SNAPSHOT pom OpenCVStudy 项目骨架 org.springframework.boot spring-boot-starter-parent 2.0.6.RELEASE UTF-8 UTF-8 1.8 Finchley.SR1 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.opencv opencv 4.5.1 system ${project.basedir}/src/main/resources/lib/opencv-451.jar org.springframework.boot spring-boot-maven-plugin gfs-maven-snapshot-repository gfs-maven-snapshot-repository https://raw.githubusercontent.com/gefangshuai/maven/master/
2、opencv\build\java目录的dll,opencv\sources\data\haarcascades数据集,按图存放。

3、测试代码
创建类 StreamUtils.java
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class StreamUtils {
/**
* 装换回编码
*
* @param correctMat
* @return
*/
public static String catToBase64(Mat correctMat) {
return bufferToBase64(toByteArray(correctMat));
}
/**
* 转换成base64编码
*
* @param buffer
* @return
*/
public static String bufferToBase64(byte[] buffer) {
return Base64Utils.encodeToString(buffer);
}
/**
* base64编码转换成字节数组
*
* @param base64Str
* @return
*/
public static byte[] base64ToByteArray(String base64Str) {
return Base64Utils.decodeFromString(base64Str);
}
/**
* base64 编码转换为 BufferedImage
*
* @param base64
* @return
*/
public static BufferedImage base64ToBufferedImage(String base64) {
BASE64Decoder Base64 = new BASE64Decoder();
try {
byte[] bytes1 = Base64.decodeBuffer(base64);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
return ImageIO.read(bais);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* mat转换成bufferedImage
*
* @param matrix
* @return
*/
public static byte[] toByteArray(Mat matrix) {
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(".jpg", matrix, mob);
return mob.toArray();
}
/**
* mat转换成bufferedImage
*
* @param matrix
* @return
*/
public static BufferedImage toBufferedImage(Mat matrix) throws IOException {
byte[] buffer = toByteArray(matrix);
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
return ImageIO.read(bais);
}
/**
* base64转Mat
*
* @param base64
* @return
* @throws IOException
*/
public static Mat base642Mat(String base64) {
return bufImg2Mat(base64ToBufferedImage(base64), BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);
}
/**
* BufferedImage转换成Mat
*
* @param original 要转换的BufferedImage
* @param imgType bufferedImage的类型 如 BufferedImage.TYPE_3BYTE_BGR
* @param matType 转换成mat的type 如 CvType.CV_8UC3
*/
public static Mat bufImg2Mat(BufferedImage original, int imgType, int matType) {
if (original == null) {
throw new IllegalArgumentException("original == null");
}
// Don't convert if it already has correct type
if (original.getType() != imgType) {
// Create a buffered image
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);
// Draw the image onto the new buffer
Graphics2D g = image.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
original = image;
} catch (Exception e) {
e.printStackTrace();
} finally {
g.dispose();
}
}
byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();
Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
mat.put(0, 0, pixels);
return mat;
}
}
测试代码
public static String markFace(String base64Images) {
String path = System.getProperty("user.dir").concat("/haarcascades/haarcascade_frontalface_alt.xml");
CascadeClassifier faceDetector = new CascadeClassifier(path);
MatOfRect faceDetections = new MatOfRect();
Mat mat = StreamUtils.base642Mat(base64Images);
faceDetector.detectMultiScale(mat, faceDetections);
if (faceDetections.toArray().length > 0) {
for (Rect rect : faceDetections.toList()) {
Imgproc.rectangle(mat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0), 3);
}
}
return StreamUtils.catToBase64(mat);
}
public static void main(String[] args) {
String base64Img = "";
String base64Back = markFace(base64Img);
}
opencv 3.4版本才能有训练器文件,4.5版本去掉了;但是训练出的数据集能通用。本人喜欢用新版,前面介绍使用的是高版本,训练自己的模型必须用3.4.X版本的。
1、下载opencv安装包【下载地址】

2、下载后选择目录安装,提取文件到本地,检查是否存在目录。
1、正样本数据图片5张(image\positive\img);创建文件info.dat(image\positive)并编辑如下内容。

img/1.jpg 1 0 0 55 55 img/2.jpg 1 0 0 55 55 img/3.jpg 1 0 0 55 55 img/4.jpg 1 0 0 55 55 img/5.jpg 1 0 0 55 55
2、负样本数据图片5张(image\negitive\img);创建bg.txt文件并编辑如下内容。

D:\tools\OpenCV\xl\image\negitive\img.jpg D:\tools\OpenCV\xl\image\negitive\img.jpg D:\tools\OpenCV\xl\image\negitive\img.jpg D:\tools\OpenCV\xl\image\negitive\img.jpg D:\tools\OpenCV\xl\image\negitive\img.jpg
3、cmd执行,生成sample.vec文件;
> D:\tools\OpenCV\opencv3.4\opencv\build\x64\vc15\bin\opencv_createsamples.exe -info D:\tools\OpenCV\xl\image\positive\info.dat -vec D:\tools\OpenCV\xl\image\sample.vec -num 5 -bgcolor 0 -bgthresh 0 -w 24 -h 24
4、生成的sample.vec和bg.txt拷贝到opencv_traincascade.exe同级目录(opencv有这个bug,不能指定目录,不然会产生报错),cmd执行;
注意:numPos 不能为正样本数量,只能小于实际数量。numNeg为负样本数量,可以大于实际数量
D:\tools\OpenCV\opencv3.4\opencv\build\x64\vc15\bin\opencv_traincascade.exe -data D:\tools\OpenCV\xl\image -vec sample.vec -bg bg.txt -numPos 3 -numNeg 7 -numStages 12 -feattureType HAAR -w 24 -h 24 -minHitRate 0.995 -maxFalseAlarmRate 0.5
执行结果:
PARAMETERS: cascadeDirName: D:\tools\OpenCV\xl\image vecFileName: sample.vec bgFileName: bg.txt numPos: 4 numNeg: 7 numStages: 12 precalcValBufSize[Mb] : 1024 precalcIdxBufSize[Mb] : 1024 acceptanceRatioBreakValue : -1 stageType: BOOST featureType: HAAR sampleWidth: 24 sampleHeight: 24 boostType: GAB minHitRate: 0.995 maxFalseAlarmRate: 0.5 weightTrimRate: 0.95 maxDepth: 1 maxWeakCount: 100 mode: BASIC Number of unique features given windowSize [24,24] : 162336 ===== TRAINING 0-stage =====Training until now has taken 0 days 0 hours 0 minutes 0 seconds. ===== TRAINING 1-stage ===== Training until now has taken 0 days 0 hours 0 minutes 0 seconds. ===== TRAINING 2-stage ===== Training until now has taken 0 days 0 hours 0 minutes 0 seconds. ===== TRAINING 3-stage ===== Training until now has taken 0 days 0 hours 0 minutes 0 seconds. ===== TRAINING 4-stage ===== Training until now has taken 0 days 0 hours 0 minutes 0 seconds. ===== TRAINING 5-stage ===== 5、执行完生成 cascade.xml
6、创建测试代码使用,可行。
public static String cascade(String base64Images) { String path = System.getProperty("user.dir").concat("/haarcascades/cascade.xml"); CascadeClassifier faceDetector = new CascadeClassifier(path); MatOfRect faceDetections = new MatOfRect(); Mat mat = StreamUtils.base642Mat(base64Images); faceDetector.detectMultiScale(mat, faceDetections); if (faceDetections.toArray().length > 0) { for (Rect rect : faceDetections.toList()) { Imgproc.rectangle(mat, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0), 3); } } return StreamUtils.catToBase64(mat); } public static void main(String[] args) { String base64Img = ""; String base64Back = cascade(base64Img); }总结
本文只是学习如何训练自己模型,选用正本和反面数据较小,实际项目中需要选用大量得样本数据图片。