如何在OpenCV中访问单通道矩阵

时间:2014-01-02 03:51:45

标签: c++ opencv image-processing

我想询问是否可以使用img.at<T>(y, x)而不是img.ptr<T>(y, x)[0]来访问单个频道矩阵

在下面的示例中,我创建了一个简单的程序来将图像复制到另一个

cv::Mat inpImg = cv::imread("test.png");
cv::Mat img;  
inpImg.convertTo(img, CV_8UC1); // single channel image

cv::Mat outImg(img.rows, img.cols, CV_8UC1);

for(int a = 0; a < img.cols; a++)
    for(int b = 0; b < img.rows; b++)
        outImg.at<uchar>(b, a) = img.at<uchar>(b, a);   // This is wrong

cv::imshow("Test", outImg);

显示的结果是错误的,但如果我将其更改为

outImg.ptr<uchar>(b, a)[0] = img.ptr<uchar>(b, a)[0];

结果是正确的。

我很困惑,因为使用img.at<T>(y, x)也应该没问题。我也试过32FC1和float,结果很相似。

1 个答案:

答案 0 :(得分:3)

虽然我知道你已经找到它,但真正的原因 - 很好地隐藏在文档中 - cv::convertTo忽略了输出类型隐含的通道数,所以当你这样做时:

inpImg.convertTo(img, CV_8UC1); 

并且,假设您的输入图像有三个通道,您实际上最终得到CV_8UC3格式,这解释了为什么您的初始解决方法成功 - 实际上,您只需要通过一个通道执行此操作:

outImg.ptr<uchar>(b, a)[0]     // takes the first channel of a CV_8UC3

这只是偶然的,因为应该像这样访问像素:

outImg.ptr<Vec3b>(b, a)[0]     // takes the blue channel of a CV_8UC3

由于两种情况下的数据仍然打包uchar,因此有效的重新解释恰好有效。

如您所述,您可以在加载时转换为灰度:

cv::imread("test.png", CV_LOAD_IMAGE_GRAYSCALE)

或者,您可以明确转换:

cv::cvtColor(inpImg, inpImg, CV_BGR2GRAY);