java基于OpenCVDnn实现人脸识别和图像分类学习
创始人
2025-06-01 10:16:29

[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),使用流行的深度学习框架(例如 CaffeTensorFlowTorchDarknet )通过预先训练的深度网络实现前向计算(即推理阶段)。这里使用的是 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) 它将图像以正确的格式输入模型,然后该函数输出一个四维矩阵。

  • 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 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

在这里插入图片描述

相关内容

热门资讯

cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...