2013-10-21 161 views
1

读取未知深度和通道编号的图像后,我想逐个访问其像素。从未知类型的cv :: Mat获得cv :: Scalar

上的OpenCV的1.x代码云:

IplImage * I = cvLoadImage("myimage.tif"); 
CvScalar pixel = cvGet2D(I, y, x); 

但OpenCV的2.X的cv::Mat.at()方法的要求,我知道图像的类型:

cv::Mat I = cv::imread("myimage.tif"); 
if(I.depth() == CV_8U && I.channels() == 3) 
    cv::Vec3b pixel = I.at<cv::Vec3b>(x, y); 
else if(I.depth() == CV_32F && I.channels() == 1) 
    float pixel = I.at<cv::float>(x, y); 

有类似cvGet2D功能如果不知道编译时的图像类型,它可以接收cv::Mat并返回cv::Scalar

回答

1

简短的回答是否定的。 C++ API中没有这样的功能。

这背后的基本原理是性能。 cv::Scalar(和CvScalar)与cv::Vec<double,4>相同。因此,对于CV_64FC4以外的任何Mat类型,您需要进行转换才能获得cv::Scalar。此外,这种方法将是一个巨大的switch,就像你的例子(你只有2个分支)。

但我想很多时候这个功能会很方便,所以为什么不用它呢?我的猜测是人们会倾向于过度使用它,导致他们算法的性能非常糟糕。因此,为了强制客户端代码使用静态类型的方法,OpenCV使访问单个像素的方法稍微简单一些。这在方便方面并不是什么大事,因为通常情况下,您实际上知道该类型,并且这在性能方面非常重要。所以,我认为这是一个很好的折衷。

+0

同意。但是缺乏这个功能会让很多C++初学者感到困惑,因为如果他们想要处理灰度和彩色图像,这需要初学者编写动态模板像素类型调度函数。 – rwong

2

我有同样的问题,我只想快速测试一下,性能不是问题。但代码的所有部分使用cv::Mat()。我做的是以下内容

Mat img; // My input mat, initialized elsewhere 

// Pretty fast operation, Will only create an iplHeader pointing to the data in the mat 
// No data is copied and no memory is mallocated. 
// The Header resides on the stack (note its type is "IplImage" not "IplImage*") 
IplImage iplImg = (IplImage)img; 

// Then you may use the old (slow converting) legacy-functions if you like 
CvScalar s = cvGet2D(&iplImg, y, x); 
1

只是一个警告:你正在使用cvLoadImage和imread默认标志。这意味着您读取的任何图像将是一个8位3通道图像。如果您想按原样读取图像(这似乎是您的意图),请使用适当的标志(IMREAD_ANYDEPTH/IMREAD_ANYCOLOR)。

2

有人谁是真正在C++初学者...

...和/或黑客谁只需要保存码打字的几秒钟就玩完the last project


cv::Mat mat = ...; // something 
cv::Scalar value = cv::mean(mat(cv::Rect(x, y, 1, 1))); 

(免责声明:此代码只是稍微少浪费而不是一个为革命事业而死的年轻人。)