欢迎访问我的GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
本篇概览
- 本文是《JavaCV的摄像头实战》系列的第十三篇,前文《JavaCV的摄像头实战之十二:性别检测》中,借助训练好的卷积神经网络模型开发出了识别性别的应用,今天在前文基础上做少量改动,实现年龄识别的功能,效果如下图:

- 应用主要功能如下图所示:

- 如果您看过《JavaCV的摄像头实战》系列的其他文章,就会发现上图中只有蓝色部分是新增内容,其余的步骤都是固定套路,《JavaCV的摄像头实战》系列的每一个应用玩的都是相同套路:别看步骤挺多,其实都是同一个流程
关于性别和年龄检测
源码下载
名称链接备注项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议git仓库地址(ssh)git@github.com:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议
- 这个git项目中有多个文件夹,本篇的源码在javacv-tutorials文件夹下,如下图红框所示:

- javacv-tutorials里面有多个子工程,《JavaCV的摄像头实战》系列的代码在simple-grab-push工程下:

准备:文件下载
准备:代码接口简介
- AbstractCameraApplication.java:主程序的抽象类,这里面定义了打开摄像头、抓取每一帧、处理每一帧的基本框架,避免每个应用都把这些事情重复做一遍
- PreviewCameraWithGenderAge.java:主程序,是AbstractCameraApplication的实现类,本次实战的核心功能人脸检测和年龄检测,都委托给它的成员变量detectService去完成
- DetectService.java:检测服务的接口,里面定义了几个重要的api,例如初始化、处理每一帧、释放资源等
- AgeDetectService.java:前文GenderDetectService的子类,仅仅是处理推理结果的逻辑与前文的性别识别略有不同,其余功能完全继承自性别识别
- 以上代码,咱们已经在前文写过一次了,今天当然不需要重复再做一次,今天是在上述代码基础上做两处小幅度修改,接下来就开始吧
改动一:主程序(PreviewCameraWithGenderAge.java)
- 卷积神经网络所需的配置和模型文件,是在主程序的main方法内设置的,上一章是性别检测,这里替换为年龄检测的文件,如下所示,请您将路径换为自己电脑上的文件路径:
- public static void main(String[] args) {
- String base = "E:\\temp\\202112\\25\\opencv\";
-
- DetectService detectService = new AgeDetectService(
- base + "haarcascade_frontalface_alt.xml",
- base + "age\\deploy.prototxt",
- base + "age\\age_net.caffemodel");
- new PreviewCameraWithGenderAge(detectService).action(1000);
- }
复制代码 改动二:检测服务实现(GenderDetectService的子类)
- 前文《性别检测》的核心功能都集中在GenderDetectService.java中,今天要做的年龄检测,除了推理结果的处理逻辑略有不同,其余功能与《性别检测》完全一致
- 所以,实现年龄检测的最简单方法就是写一个子类继承GenderDetectService,这个子类中只有神经网络推理结果的处理逻辑,完整代码如下,注释中已经有了详细说明,就不多赘述了:
[code]package com.bolingcavalry.grabpush.extend;import lombok.extern.slf4j.Slf4j;import org.bytedeco.javacpp.DoublePointer;import org.bytedeco.opencv.opencv_core.Mat;import org.bytedeco.opencv.opencv_core.Point;import static org.bytedeco.opencv.global.opencv_core.minMaxLoc;/** * @author willzhao * @version 1.0 * @description 检测年龄的服务 * @date 2021/12/3 8:09 */@Slf4jpublic class AgeDetectService extends GenderDetectService { /** * 设置训练模型时划分的年龄段,所以推理结果也是这样的年龄段 */ private static final String[] AGES = new String[]{"0-2", "4-6", "8-13", "15-20", "25-32", "38-43", "48-53", "60-"}; /** * 构造方法,在此指定proto和模型文件的下载地址 * * @param classifierModelFilePath * @param cnnProtoFilePath * @param cnnModelFilePath */ public AgeDetectService(String classifierModelFilePath, String cnnProtoFilePath, String cnnModelFilePath) { super(classifierModelFilePath, cnnProtoFilePath, cnnModelFilePath); } @Override protected String getDescriptionFromPredictResult(Mat prob) { DoublePointer pointer = new DoublePointer(new double[1]); Point max = new Point(); // 把prob理解为一个数组, // 第一个元素是"0-2"的置信度 // 第二个元素是"4-6"的置信度 // 第三个元素是"8-13"的置信度 // 第四个元素是"15-20"的置信度 // ... // 第八个元素是"60-"的置信度 // minMaxLoc方法帮忙我们找出了置信度最高的元素,max是元素位置,pointer是这个元素的置信度 minMaxLoc(prob, null, pointer, null, max, null); // 如果置信度太低,那就是"难以置信",就返回空字符串 if (pointer.get() |