2013-10-21 164 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))); 

(免責聲明:此代碼只是稍微少浪費而不是一個爲革命事業而死的年輕人。)