如何向OpenCV DNN输入多类型异构模型输入(含不同尺寸图像与数组)
问题解决:OpenCV加载多输入TensorFlow模型报错处理
问题描述
加载TensorFlow的.pb模型,模型包含4类输入:
- 256×256的图像
- 两个64×64的图像
- 长度为4的数组
输出为长度2的数组。尝试将所有输入转成blob后放入vector,调用net.setInput()传入vector再执行forward()时触发断言错误:
libc++abi: terminating with uncaught exception of type cv::Exception: OpenCV(4.5.5) /tmp/opencv-20220714-27380-1eyun69/opencv-4.5.5/modules/core/src/matrix_wrap.cpp:81: error: (-215:Assertion failed) 0 <= i && i < (int)v.size() in function 'getMat_'
原尝试代码:
cv::dnn::Net net = cv::dnn::readNetFromTensorflow("model/mfg.pb"); cv::Mat input_face = cv::dnn::blobFromImage(face, 1, cv::Size(256,256), cv::Scalar(104,177,123), true, false); cv::Mat input_leye = cv::dnn::blobFromImage(leye, 1, cv::Size(64,64), cv::Scalar(104,177,123), true, false); cv::Mat input_reye = cv::dnn::blobFromImage(reye, 1, cv::Size(64,64), cv::Scalar(104,177,123), true, false); cv::Mat input_bbox = (cv::Mat1d(1,4) << face_bbox[0], face_bbox[1], face_bbox[2], face_bbox[3]); std::vector<cv::Mat> input_image = {input_face, input_leye, input_reye, input_bbox}; net.setInput(input_image); net.forward();
错误原因
- 未绑定输入节点名称:直接传入vector的方式无法确保输入与模型定义的输入节点一一对应,模型可能找不到匹配的输入,导致索引越界。
- 第四个输入格式不匹配:模型大概率要求输入为
float32类型,但代码中用Mat1d创建了double类型的矩阵;同时输入维度不符合模型要求(图像输入是[1,3,H,W]的blob格式,数组输入也需要保持类似的批量维度,即[1,4])。
解决方案
步骤1:获取模型输入节点名称
先通过OpenCV获取模型所有输入节点的名称,确保后续绑定正确:
// 打印所有输入节点的名称和形状 auto inputs = net.getInputs(); for (auto &input : inputs) { std::cout << "Input name: " << input.name() << ", shape: " << input.size() << std::endl; }
运行这段代码可以得到每个输入节点的准确名称,比如可能是input_face、input_leye、input_reye、input_bbox这类命名。
步骤2:逐个设置输入并匹配名称
不要用vector批量传入,而是调用net.setInput(blob, inputName)逐个绑定输入,同时修正第四个输入的格式:
cv::dnn::Net net = cv::dnn::readNetFromTensorflow("model/mfg.pb"); // 处理图像输入,保持原blob转换逻辑 cv::Mat input_face = cv::dnn::blobFromImage(face, 1, cv::Size(256,256), cv::Scalar(104,177,123), true, false); cv::Mat input_leye = cv::dnn::blobFromImage(leye, 1, cv::Size(64,64), cv::Scalar(104,177,123), true, false); cv::Mat input_reye = cv::dnn::blobFromImage(reye, 1, cv::Size(64,64), cv::Scalar(104,177,123), true, false); // 修正bbox输入:转成float32类型,生成[1,4]的blob格式 cv::Mat bbox_mat(1, 4, CV_32F); float* bbox_data = bbox_mat.ptr<float>(); bbox_data[0] = face_bbox[0]; bbox_data[1] = face_bbox[1]; bbox_data[2] = face_bbox[2]; bbox_data[3] = face_bbox[3]; cv::Mat input_bbox = cv::dnn::blobFromImage(bbox_mat, 1.0, cv::Size(), cv::Scalar(), false, false); // 用步骤1获取的实际输入名称绑定每个输入 net.setInput(input_face, "input_face"); net.setInput(input_leye, "input_leye"); net.setInput(input_reye, "input_reye"); net.setInput(input_bbox, "input_bbox"); // 执行推理并提取结果 cv::Mat output = net.forward(); float* output_data = output.ptr<float>(); std::cout << "Output: [" << output_data[0] << ", " << output_data[1] << "]" << std::endl;
关键注意事项
- 输入名称必须和模型定义的完全一致,包括大小写、下划线等,否则模型无法识别输入。
- 所有输入的数据类型必须匹配模型要求,大部分TensorFlow模型默认使用
float32,避免用double类型。 - 输入维度要符合模型要求:图像输入是
[batch_size, channels, height, width],数组输入一般是[batch_size, feature_size],确保批量维度(第一个维度)存在。
内容的提问来源于stack exchange,提问作者renoir
相关产品推荐
相关产品推荐

