从未知类型的cv :: Mat获取cv :: Scalar

时间:2013-10-21 18:18:20

标签: c++ opencv

在读取未知深度和频道编号的图像后,我想逐个访问其像素。

在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

4 个答案:

答案 0 :(得分: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 :(得分:2)

对于真正是C ++初学者的人......

...和/或只需要保存几秒钟的代码输入以完成the last project

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

(免责声明:此代码仅比死于革命事业的年轻人浪费得少。)

答案 2 :(得分:1)

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

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

但我想这个功能很常见,所以为什么不这样做呢?我的猜测是人们倾向于过度使用它,导致他们的算法性能非常差。因此,OpenCV使得访问单个像素的便利性变得不那么方便,以便强制客户端代码使用静态类型的方法。这并不是一件非常方便的事情,因为通常情况下,你实际上是静态地知道这种类型,而且这在性能上是非常重要的。所以,我认为这是一个很好的权衡。

答案 3 :(得分:1)

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