You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java+OpenCV实现年龄性别识别时出现Vector Subscript out of range错误

问题分析与修复

核心错误原因

你遇到的Vector Subscript out of range错误,根源是对OpenCV DNN人脸检测模型输出的detections矩阵维度理解错误:

  • TensorFlow版本的人脸检测模型输出是4维矩阵,形状为[1, 1, N, 7],其中N是检测到的候选框数量,每个候选框包含7个数据:[image_id, label, confidence, x1, y1, x2, y2]
  • 你当前的代码错误地用2维索引访问4维矩阵,并且循环条件错误地使用了矩阵的height(实际为1),导致越界访问。

另外还有两个次要问题:

  1. 未判断cap.read(frame)是否成功,若摄像头读取失败会生成空Mat,后续操作会报错
  2. cap.release()放在while(true)循环内部,第一次循环就释放了摄像头,后续循环无法读取帧

修复后的代码

package AgeGenderCV;

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Core;
import org.opencv.core.Point;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;

public class AgeGenderCV {
    private static final String[] GENDER_LIST = {"Male", "Female"};
    private static final String[] AGE_LIST = {"(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)", "(38-43)", "(48-53)", "(60-100)"};
    private static final double[] MODEL_MEAN_VALUES = {78.4263377603, 87.7689143744, 114.895847746};
    private static final double CONFIDENCE_THRESHOLD = 0.7;

    public void ProcessImage(){
        // Load networks
        Net faceNet = Dnn.readNetFromTensorflow("opencv_face_detector_uint8.pb", "opencv_face_detector.pbtxt");
        Net ageNet = Dnn.readNetFromCaffe("age_deploy.prototxt", "age_net.caffemodel");
        Net genderNet = Dnn.readNetFromCaffe("gender_deploy.prototxt", "gender_net.caffemodel");
        
        // Open camera stream
        VideoCapture cap = new VideoCapture(0);
        // 检查摄像头是否成功打开
        if (!cap.isOpened()) {
            System.err.println("无法打开摄像头");
            return;
        }

        while (true) {
            Mat frame = new Mat();
            // 检查帧是否读取成功
            if (!cap.read(frame) || frame.empty()) {
                System.err.println("无法读取帧,退出循环");
                break;
            }
            
            List<Rect> bboxes = new ArrayList<>();
            Size size = new Size(300,300);
            Scalar scalar = new Scalar(104, 117, 123);
            
            Mat blob = Dnn.blobFromImage(frame, 1.0, size, scalar, false, false);
            faceNet.setInput(blob);
            Mat detections = faceNet.forward();
            
            // 获取候选框数量:detections是[1,1,N,7],第三维的大小是N
            int numDetections = detections.size(2);
            for (int i = 0; i < numDetections; i++) {
                // 正确访问4维矩阵的元素:[0, 0, i, 2]对应confidence
                double confidence = detections.get(new int[]{0, 0, i, 2})[0];
                if (confidence > CONFIDENCE_THRESHOLD) {
                    // 提取坐标
                    double x1 = detections.get(new int[]{0, 0, i, 3})[0] * frame.cols();
                    double y1 = detections.get(new int[]{0, 0, i, 4})[0] * frame.rows();
                    double x2 = detections.get(new int[]{0, 0, i, 5})[0] * frame.cols();
                    double y2 = detections.get(new int[]{0, 0, i, 6})[0] * frame.rows();
                    
                    Rect bbox = new Rect((int)x1, (int)y1, (int)(x2-x1), (int)(y2-y1));
                    bboxes.add(bbox);
                    Imgproc.rectangle(frame, new Point(x1, y1), new Point(x2, y2), new Scalar(0, 255, 0), 2);
                }
            }

            if (bboxes.isEmpty()) {
                System.out.println("未检测到人脸,继续下一帧");
                continue;
            }

            for (Rect bbox : bboxes) {
                Mat face = new Mat(frame, bbox);
                Size sizeb = new Size(227,227);
                Scalar scalarb = new Scalar(MODEL_MEAN_VALUES);
                blob = Dnn.blobFromImage(face, 1.0, sizeb, scalarb, false);
                
                // 性别检测
                genderNet.setInput(blob);
                Mat genderPreds = genderNet.forward();
                int genderIdx = Core.minMaxLoc(genderPreds).maxLoc.x > 0 ? 1 : 0;
                String gender = GENDER_LIST[genderIdx];
                System.out.println("性别 : " + gender + ", 置信度 = " + genderPreds.get(0, genderIdx)[0]);

                // 年龄检测
                ageNet.setInput(blob);
                Mat agePreds = ageNet.forward();
                agePreds = agePreds.reshape(1, 1);
                Core.MinMaxLocResult mm = Core.minMaxLoc(agePreds);
                int ageIdx = (int) mm.maxLoc.x;  
                System.out.println("年龄 : " + AGE_LIST[ageIdx] + ", 置信度 = " + agePreds.get(0, ageIdx)[0]);
            }
        }
        // 循环结束后释放摄像头
        cap.release();
    }
    
    public static void main(String args[])
    {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        AgeGenderCV example = new AgeGenderCV();
        example.ProcessImage();
    }
}

关键修改点

  1. 修正detections矩阵访问:使用detections.get(new int[]{0, 0, i, 2})来访问4维矩阵的元素,获取候选框的置信度和坐标
  2. 正确获取候选框数量:通过detections.size(2)获取第三维的大小(即检测到的候选框总数)
  3. 添加摄像头和帧检查:判断cap.isOpened()和cap.read(frame)是否成功,避免空矩阵操作
  4. 调整cap.release()位置:移到while循环外部,确保循环结束后再释放摄像头
  5. 修正性别检测索引:通过minMaxLoc获取最大置信度的索引,避免直接用genderPreds.get(0,0)[0]导致的类型转换错误

内容的提问来源于stack exchange,提问作者Tom C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 14:51:24