[OpenCV实战]2 人脸识别算法对比 - 落痕的寒假 - 博客园 (cnblogs.com)
java高度人脸识别,再也不用受python的气了!_小明程序猿的博客-CSDN博客
OpenCV 人脸检测详解(仅需2行代码学会人脸检测) - 掘金 (juejin.cn)
OpenCV基础(15)OpenCV DNN模块的深度学习:权威指南_求则得之,舍则失之的博客-CSDN博客
汇总 | OpenCV DNN模块中支持的分类网络 - 腾讯云开发者社区-腾讯云 (tencent.com)
java-opencv-训练自己的物体分类器 - 锐洋智能 - 博客园 (cnblogs.com)
DenseNet-121-昇腾社区 (hiascend.com)
之前的文章地址:http://t.csdn.cn/19X9Q
本次开发语言:Java
其实下载下来的opencv安装包是自带 Haar Cascade人脸分类器的,不过这个识别错误率挺高的。当人脸有遮挡,侧脸,嘴型变化等,都会导致识别失败。
OpenCVDnn 可能综合来说是最好的方法。
OpenCV 深度神经网络(Deep Neural Networks,DNN),使用流行的深度学习框架(例如 Caffe
、TensorFlow
、Torch
和 Darknet
)通过预先训练的深度网络实现前向计算(即推理阶段)。这里使用的是 ResNet-10
网络的 Single Shot MultiBox Detector (SSD) 框架
这里使用的模型是 ResNet
必备文件:
-
人脸检测器 (FP16):Caffe 实现的浮点 16 版本,为了使用此检测器,首先下载模型文件(deploy.prototxt)和配置文件(res10_300x300_ssd_iter_140000_fp16.caffemodel);
-
人脸检测器 (UINT8):TensorFlow 实现的 8 位量化版本,为了使用此检测器,首先下载模型文件(opencv_face_detector.pbtxt)和配置文件(opencv_face_detector_uint8.pb)。
import org.opencv.core.*;
import org.opencv.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
public class Demo {
public static void main(String[] args) {
imageFaceDetectionDnn();
}
public static void imageFaceDetectionDnn() {
//加载opencv本地库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//加载预训练好的模型
Net net = Dnn.readNetFromCaffe("E:\\电脑文件路径\\deploy.prototxt",
"E:\\电脑文件路径\\res10_300x300_ssd_iter_140000_fp16.caffemodel");
//读取图片
String imgPath = "C:\\Users\\A80759\\Pictures\\Saved Pictures\\20200924194319998.jpg";
Mat image = Imgcodecs.imread(imgPath);
//为了获得最佳精度,必须分别对蓝色、绿色和红色通道执行 `(104, 177, 123)` 通道均值减法
Mat inputBlob = Dnn.blobFromImage(image, 1.0f,
new Size(image.size().width, image.size().height),
new Scalar(104, 117, 123), false, false);
net.setInput(inputBlob);
Mat res = net.forward();
Mat faces = res.reshape(1, res.size(2));
System.out.println("faces" + faces);
float [] data = new float[7];
System.out.println("识别到人脸数:" + faces.rows());
for (int i=0; i<faces.rows(); i++) {
faces.get(i, 0, data);
float confidence = data[2];
if (confidence > 0.2f) {
int left = (int)(data[3] * image.cols());
int top = (int)(data[4] * image.rows());
int right = (int)(data[5] * image.cols());
int bottom = (int)(data[6] * image.rows());
System.out.println("("+left + "," + top + ")("+right+","+bottom+") " + confidence);
Imgproc.rectangle(image, new Point(left,top), new Point(right,bottom), new Scalar(0,200,0), 3);
}
}
Imgcodecs.imwrite("C:\\电脑文件路径\\new.jpg", image);
// 展示图片
HighGui.imshow("人脸识别", image);
HighGui.waitKey(0);
}
}
blobFromImage(image, scalefactor=None, size=None, mean=None, swapRB=None, crop=None, ddepth=None)
它将图像以正确的格式输入模型,然后该函数输出一个四维矩阵。
- image:这是我们刚刚使用imread()函数读取的输入图像。
- scalefactor:这个值根据提供的值缩放图像。它的默认值是1,这意味着不执行缩放。
- size:这是图像将被调整为的大小。我们提供了224×224的大小,这是大多数在ImageNet数据集上训练的分类模型所期望的大小。
- mean:这一参数非常重要。这些实际上是从图像的RGB颜色通道中减去的平均值。这将输入归一化并使最终输入对不同的照明尺度具有不变性。
- swapRB:表示在3通道图像中是否交换第一个和最后一个通道。
- crop:图像在调整大小后是否被裁剪,如果crop为真,调整输入图像大小,调整大小后的一边等于相应的尺寸,另一面等于相应的尺寸或比相应的尺寸更大。然后,从中心进行裁剪。
- ddepth:输出blob的深度。选择CV_32F或CV_8U
示例1
控制台输出(每个方框上下左右的坐标以及识别率)
(589,258)(616,288) 0.9975394
(124,206)(152,242) 0.9969188
(80,249)(106,286) 0.99600464
(382,199)(409,235) 0.99527127
(312,199)(338,235) 0.99450785
(394,244)(416,273) 0.99186796
(352,220)(377,255) 0.990858
(270,246)(296,280) 0.9882124
(56,226)(81,255) 0.9871501
(519,244)(542,274) 0.98257476
(568,232)(590,260) 0.9770947
(185,203)(210,238) 0.95680207
(224,201)(248,230) 0.9469372
(183,262)(212,301) 0.9389939
(660,216)(684,246) 0.92794573
(468,229)(495,263) 0.8848143
(27,255)(53,284) 0.8775511
(265,209)(284,240) 0.8663978
(496,226)(518,252) 0.85343516
(442,235)(463,263) 0.75329876
(668,164)(690,191) 0.69498074
(324,175)(344,197) 0.3945995
(28,179)(44,203) 0.34156087
(378,171)(395,197) 0.27158168
这里把识别率调整为 大于0.2 即认为是人脸
示例2
控制台输出
(1156,374)(1190,417) 0.9992472
(934,274)(960,308) 0.99852234
(557,394)(587,429) 0.99838257
(1385,332)(1423,373) 0.99836737
(1393,386)(1431,428) 0.99816304
(333,368)(363,404) 0.9981445
(1276,378)(1312,420) 0.99808145
(756,266)(787,300) 0.99715877
(270,336)(300,372) 0.996067
(1279,312)(1312,351) 0.9959883
(431,346)(460,382) 0.9959792
(726,374)(754,414) 0.995004
(791,314)(819,352) 0.99491924
(576,273)(602,308) 0.9948049
(296,416)(329,453) 0.99422365
(941,389)(971,430) 0.9940135
(377,320)(407,356) 0.99389946
(474,421)(506,460) 0.9935196
(1243,247)(1274,286) 0.993379
(1047,380)(1076,425) 0.9932128
(233,384)(268,421) 0.99236125
(185,447)(220,483) 0.9923139
(1190,307)(1222,345) 0.9916454
(624,315)(651,353) 0.9911696
(1030,269)(1056,304) 0.99091816
(680,270)(708,305) 0.9895411
(467,295)(494,330) 0.9886185
(131,386)(164,426) 0.98816407
(702,329)(733,368) 0.9881606
(397,414)(428,454) 0.9875408
(1129,270)(1160,306) 0.9863598
(852,278)(878,312) 0.9858732
(985,321)(1014,361) 0.980375
(528,326)(557,360) 0.9786332
(1355,254)(1384,286) 0.9774844
(830,386)(860,427) 0.9756031
(881,328)(911,371) 0.9755162
(632,395)(663,437) 0.9643314
(66,449)(108,488) 0.96184486
(1081,316)(1111,356) 0.95269746
这里把识别率调整为 大于0.9 即认为是人脸
示例3
这里把识别率调整为 大于0.99 即认为是人脸
控制台输出
(1372,292)(1488,441) 0.9999876
(83,517)(236,716) 0.9999343
(333,260)(446,414) 0.99986064
(516,310)(612,456) 0.9998554
(394,458)(550,648) 0.9995573
(1126,333)(1234,483) 0.99942386
(898,537)(1044,727) 0.9992487
(1089,566)(1235,751) 0.9991135
(1345,550)(1487,734) 0.9987877
(945,307)(1055,440) 0.99821436
(645,532)(788,719) 0.998075
(718,346)(825,482) 0.9980019
图片分类
本次使用的模型是 DenseNet-121
. 详解DenseNet(密集连接的卷积网络)
- DenseNet_121.prototxt
- DenseNet_121.caffemodel
已经做好分类的文本
- classification_classes_ILSVRC2012.txt
import cn.hutool.core.io.FileUtil;
import org.opencv.core.*;
import org.opencv.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.nio.charset.Charset;
import java.util.List;
public class Demo2 {
public static void main(String[] args) {
//加载opencv本地库
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//读取ImageNet类名
List<String> strings = FileUtil.readLines("E:\\xxx\\classification_classes_ILSVRC2012.txt",
Charset.defaultCharset());
Net net = Dnn.readNetFromCaffe("E:\\xxx\\DenseNet_121.prototxt",
"E:\\xxx\\DenseNet_121.caffemodel");
//读取图片
String imgPath = "E:\\xxx\\af0cc6c118a37e9170db1c2ade2ac9c3.jpg";
Mat image = Imgcodecs.imread(imgPath);
Mat inputBlob = Dnn.blobFromImage(image, 0.01f,
new Size(image.size().width, image.size().height),
new Scalar(104, 117, 123), false, false);
net.setInput(inputBlob);
Mat res = net.forward();
Mat temp = res.reshape(1, 1);
Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(temp);
Point maxLoc = minMaxLocResult.maxLoc;
double x = maxLoc.x;
Double d = new Double(x);
int classId = d.intValue();
double confidence = minMaxLocResult.maxVal;
System.out.println(classId + ":" + confidence);
Imgproc.putText(image, strings.get(classId)+" "+confidence, new Point(100, 150),
Imgproc.CHAIN_APPROX_SIMPLE, 0.5, new Scalar(0, 255, 0, 0));
HighGui.imshow("图像分类", image);
HighGui.waitKey(0);
}
}
结果1
结果2
结果3
还是会出现失误,识别错误率存在
结果4