1

在读取了未知深度和通道号的图像后,我想一个一个地访问它的像素。

在 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

4 回答 4

2

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

...和/或只需要节省几秒钟的代码输入来完成最后一个项目的黑客


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

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

于 2014-10-31T22:14:13.693 回答
1

最简洁的答案是不。C++ API 中没有这样的功能。

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

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

于 2013-10-22T08:14:10.937 回答
1

我有同样的问题,我只是想快速测试一些东西,性能不是问题。但是代码的所有部分都使用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 );
于 2013-10-22T14:41:24.150 回答
1

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

于 2013-10-23T08:16:58.477 回答