返回

JavaCV摄像头实战十三:让你的摄像头也会算年龄

后端

在前面《性别检测》的基础上,修改少量代码,即可实现年龄检测,并且会将检测结果的每一帧输出在预览窗口,产生实时识别的效果。

import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_dnn.Net;
import org.bytedeco.opencv.opencv_objdetect.CascadeClassifier;

import java.io.IOException;

public class AgeDetection {

    private static final String MODEL_PATH = "models/age_deploy.prototxt";
    private static final String WEIGHTS_PATH = "models/age_net.caffemodel";
    private static final String FACE_DETECTOR_PATH = "models/haarcascade_frontalface_default.xml";

    public static void main(String[] args) throws IOException, FrameGrabber.Exception {
        // 加载模型
        Net net = readCaffeModel(MODEL_PATH, WEIGHTS_PATH);
        CascadeClassifier faceDetector = new CascadeClassifier(FACE_DETECTOR_PATH);

        // 打开摄像头
        FrameGrabber grabber = FrameGrabber.createDefault(0);
        grabber.start();

        // 创建一个窗口来显示视频流
        CanvasFrame canvasFrame = new CanvasFrame("摄像头年龄检测");

        // 创建一个转换器来将Frame转换为Mat对象
        OpenCVFrameConverter converter = new OpenCVFrameConverter.ToMat();

        // 无限循环以捕获视频流
        while (true) {
            // 捕获一帧视频
            Frame frame = grabber.grab();

            // 将帧转换为Mat对象
            Mat mat = converter.convert(frame);

            // 检测人脸
            MatOfRect faces = new MatOfRect();
            faceDetector.detectMultiScale(mat, faces);

            // 循环检测到的每张人脸
            for (Rect face : faces.toArray()) {
                // 提取人脸图像
                Mat faceImage = new Mat(mat, face);

                // 预处理人脸图像
                Mat blob = Dnn.blobFromImage(faceImage, 1.0, new Size(224, 224), new Scalar(78.4263377608, 87.7689143744, 114.895847746));

                // 将人脸图像输入模型
                net.setInput(blob);

                // 预测年龄
                Mat output = net.forward();

                // 获取预测结果
                float[] probabilities = output.ptrFloats(0);

                // 找到最大概率对应的年龄组
                int maxIndex = 0;
                float maxProbability = 0;
                for (int i = 0; i < probabilities.length; i++) {
                    if (probabilities[i] > maxProbability) {
                        maxIndex = i;
                        maxProbability = probabilities[i];
                    }
                }

                // 将年龄组映射到年龄范围
                String ageRange = getAgeRange(maxIndex);

                // 在人脸上绘制年龄
                Rect rectangle = face;
                int x = rectangle.x();
                int y = rectangle.y();
                int width = rectangle.width();
                int height = rectangle.height();
                rectangle.x(x + width / 2);
                rectangle.y(y - height / 2);
                rectangle.width(50);
                rectangle.height(20);
                Dnn.rectangle(mat, rectangle, new Scalar(0, 255, 0), 2);

                // 将年龄添加到人脸上
                String text = "Age: " + ageRange;
                putText(mat, text, new Point(x + width / 2, y - height / 2 - 5), Font.HERSHEY_SIMPLEX, 0.5, new Scalar(0, 255, 0), 2);
            }

            // 显示结果
            canvasFrame.showImage(converter.convert(mat));
        }

        // 释放资源
        grabber.stop();
        canvasFrame.dispose();
    }

    private static Net readCaffeModel(String modelPath, String weightsPath) throws IOException {
        Net net = Dnn.readNetFromCaffe(modelPath, weightsPath);
        return net;
    }

    private static String getAgeRange(int index) {
        String[] ageRanges = {"0-2", "4-6", "8-12", "15-20", "25-32", "38-43", "48-53", "60-100"};
        return ageRanges[index];
    }
}

以上代码的功能是:

  1. 加载模型。首先,我们需要加载训练好的年龄检测模型。模型包含两个部分:模型结构和模型权重。模型结构定义了模型的网络结构,模型权重包含了训练过程中学习到的参数。
  2. 打开摄像头。接下来,我们需要打开摄像头以获取视频流。
  3. 创建一个窗口来显示视频流。我们需要创建一个窗口来显示捕获到的视频流。
  4. 创建一个转换器来将Frame转换为Mat对象。我们需要创建一个转换器来将Frame对象转换为Mat对象。Mat对象是OpenCV中的一种数据结构,它可以表示图像或视频帧。
  5. 无限循环以捕获视频流。然后,我们需要进入一个无限循环来捕获视频流。
  6. 捕获一帧视频。在循环中,我们需要捕获一帧视频。
  7. 将帧转换为Mat对象。接下来,我们需要将帧转换为Mat对象。
  8. 检测人脸。然后,我们需要使用人脸检测器检测人脸。
  9. 循环检测到的每张人脸。对于检测到的每张人脸,我们需要进行以下操作:
    • 提取人脸图像。
    • 预处理人脸图像。
    • 将人脸图像输入模型。
    • 预测年龄。
    • 获取预测结果。
    • 将预测结果映射到年龄范围。
    • 在人脸上绘制年龄。
  10. 显示结果。最后,我们需要将结果显示在窗口中。

通过以上步骤,我们可以实现摄像头年龄检测功能。