在读取未知深度和频道编号的图像后,我想逐个访问其像素。
在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
?
答案 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)
...和/或只需要保存几秒钟的代码输入以完成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)。