如何从OpenCV DNN生成的4维cv::Mat blob中提取单个颜色通道
你遇到的问题根源是对OpenCV DNN模块输出的blob内存排布规则理解有误,以及构造提取通道的Mat时参数设置错误。
OpenCV dnn::blobFromImage的存储逻辑
cv::dnn::blobFromImage 默认输出NCHW排布的4维Mat,4个维度依次为:
- 第0维:batch size,你的场景下固定为1
- 第1维:通道数,你的场景下为3,因为你设置了
swapRB=false,所以通道顺序为B、G、R - 第2维:输入图像高度,你的场景下为224
- 第3维:输入图像宽度,你的场景下为244
内存是连续紧凑存储的,存储顺序为:先完整存储B通道的所有224*244个uint8像素,再完整存储G通道的所有像素,最后完整存储R通道的所有像素,和普通OpenCV cv::Mat默认的BGR交错存储(每个像素点按B、G、R三个值依次存储)逻辑完全不同。
现有代码的错误点
- 构造
blueImg时指定了CV_8UC3类型,相当于把连续存储的单通道B像素数据,按照每3个值对应一个像素的3通道格式解析,必然会出现内容错乱,也就是你现在看到的异常输出结果 - 代码存在语法遗漏:构造函数最后一个参数的右括号缺失,编译阶段会报错
正确的实现方案
单通道提取代码
// 先确认blob维度符合预期,可选调试代码 CV_Assert(blob.dims == 4 && blob.size[0] == 1 && blob.size[1] ==3); int h = blob.size[2]; int w = blob.size[3]; // 提取B通道(第1个通道,索引0) cv::Mat blueImg(h, w, CV_8UC1, blob.ptr<uint8_t>(0, 0)); // 提取G通道(第2个通道,索引1) cv::Mat greenImg(h, w, CV_8UC1, blob.ptr<uint8_t>(0, 1)); // 提取R通道(第3个通道,索引2) cv::Mat redImg(h, w, CV_8UC1, blob.ptr<uint8_t>(0, 2));
还原为普通BGR三通道Mat(可选,用于和原图对比验证)
cv::Mat recoveredBgr; std::vector<cv::Mat> channels = {blueImg, greenImg, redImg}; cv::merge(channels, recoveredBgr); // 此时可直接imshow查看recoveredBgr,和原始输入m_inputImg完全一致
额外注意事项
- 如果调用
blobFromImage时设置了swapRB=true,则通道顺序变为R、G、B,提取后merge时需要调整通道顺序对应索引 - 如果传入了非1的缩放系数、或者设置了减均值参数,提取的像素值会和原始图像有差异,属于正常预处理结果
- 如果设置了
crop=true,blob存储的是裁剪后的图像内容,和原图大小会有差异
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

