[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; ifaces.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)
它将图像以正确的格式输入模型,然后该函数输出一个四维矩阵。
控制台输出(每个方框上下左右的坐标以及识别率)
(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 即认为是人脸
控制台输出
(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 即认为是人脸
这里把识别率调整为 大于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(密集连接的卷积网络)
已经做好分类的文本
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 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