2014-01-16 37 views
3

我注意到,使用convertTo將矩陣從32位轉換爲16位「rounds」數字到上層。因此,源矩陣中大於0x0000FFFF的值將在目標矩陣中設置爲0xFFFF。OpenCV 2.4.7 Mat :: convertTo()32位到16位截尾

我想爲我的應用程序,而不是屏蔽值,設置在目標只是2 LSB的值。

下面是一個例子:

Mat mat32; 
Mat mat16; 

mat32 = Mat(2,2,CV_32SC1); 

for(int y = 0; y < 2; y++) 
    for(int x = 0; x < 2; x++) 
    mat32.at<unsigned int>(cv::Point(x,y)) = 0x0000FFFE + (y*2+x); 

mat32.convertTo(mat16, CV_16UC1); 

該矩陣具有這些值:

32 bits matrix: 
0000FFFE  0000FFFF 
00010000  00010001 

16 bits matrix: 
0000FFFE  0000FFFF 
0000FFFF  0000FFFF 

在16位矩陣的第二行我想有

00000000 00000001 

我可以通過逐個值地掃描源矩陣並掩蔽值來做到這一點,但性能很低。

有沒有OpenCV功能可以做到這一點?

感謝大家!

MIX

+1

根你的問題的原因是OpenCV在cv :: Mat :: convertTo()方法中應用了cv :: saturate_cast。這在文檔中有明確說明。 – sansuiso

回答

1

沒有OpenCV的功能(即我所知道的)像你想它會進行轉換,所以無論是你自己的代碼,或像你說你去通過掩膜步驟首先要去除16高位。

可以使用C++中的bitwise_and或C中的cvAndS來應用掩碼。請參閱here

你也可以讓你的手寫代碼更有效率。一般來說,您應該避免OpenCV像素訪問器出現在循環中,因爲它們的性能不佳。我沒有一個OpenCV的安裝在眼前所以這可能是slighlty掉 - 的想法是直接使用data領域,step這是每行的字節數:

for(int y = 0; y < mat32.height; ++) { 
    int* row = (int*)((char*)mat32.data + y * mat32.step); 
    for(int x = 0; x < mat32.step/ 4) 
    row[x] &= 0xffff; 

然後,一旦掩碼被應用,所有值都適合16位,並且convertTo將只截斷16位高位。

另一種方案是用手工編寫轉換:

mat16.resize(mat32.size()); 
for(int y = 0; y < mat32.height; ++) { 
    const int* row32 = (const int*)((char*)mat32.data + y * mat32.step); 
    short*  row16 = (short*) ((char*)mat16.data + y * mat16.step); 
    for(int x = 0; x < mat32.step/ 4) 
    row16[x] = short(row32[x]); 
+0

好的,沒有內置的函數...我已經創建了轉換函數。使用'數據'字段似乎更有效一些(雖然可讀性較差)。我沒有使用它,因爲我無法在Mat類中找到'widthStep'參數,就像IplImage(我迄今在OpenCV 1.x中使用的類);比我注意到'step'參數。愚蠢的我! –

+0

確實,在「Mat」類中,它被稱爲「step」,我會糾正我的答案。 – Antoine

2

這是可以做到,但是這需要一個有點使壞,所以它是由你來使用這種方法還是不行。所以這是如何完成的:

對於這個例子,我們可以創建1000x1000的32位矩陣,並將其所有值設置爲65541(= 256 * 256 + 5)。所以在轉換之後,我們希望有一個填充五個的矩陣。

Mat M1(1000, 1000, CV_32S, Scalar(65541)); 

這裏是招:

Mat M2(1000, 1000, CV_16SC2, M1.data); 

我們創建的矩陣M2較上年內存緩衝區爲M1,但M2「想」這是2通道16位圖像的緩衝區。現在最後要做的是將你需要的頻道複製到你需要的地方。這可以通過split()或mixChannels()函數完成。例如:

Mat M3(1000, 1000, CV_16S); 
int fromto[] = {0,0}; 
Mat inpu[] = {M2}, outpu[] = {M3}; 
mixChannels(inpu, 1, outpu, 1, fromto, 1); 
cout << M3.at<short>(10,10) << endl; 

燁我知道mixChannels的格式看起來怪異,使代碼更少可讀,但它的作品...如果你喜歡拆分()函數:

vector<Mat> v; 
split(M2,v); 
cout << v[0].at<short>(10,10) << " " << v[1].at<short>(10,10) << endl; 
+1

讓我讀你的帖子50多次... –

+0

我不確定你的評論是什麼意思。如果您的意思不清楚,我可以嘗試重新解釋。 –

+0

不,沒關係。這與我平常的做法相去甚遠,所以我已經很多時間閱讀它來了解正在發生的事情。 –