cvGetRawData()的奇怪問題
最近在使用JNI,設法從Java中調用OpenCV的函數。在OpenCV中圖像是以IplImage的形式封裝的。IplImage是一個Header,定義了圖像的各種屬性,通過查看IplImage結構體我們可以發現,圖像數據實際上也是在一段連續的內存中分配的,IplImage.imageData就是指向這塊數據的指針。隨便訪問一個結構體的成員是不好的,所以OpenCV提供了訪問原始數據RawData的方法
void cvGetRawData( const CvArr* arr, uchar** data, int* step=NULL, CvSize* roi_size=NULL );
典型的,對于一個三通道,顏色深度為256的圖像img,假設我們知道它的width,height,為了取得其RawData,可以定義一個數組data,并調用cvGetRawData()函數,將RawData存放到data中:
那么,這個時候,data內部是如何組織的呢?按照一般的邏輯,它應該是這樣
{{34,123,90},{34,122,87},{21,123,88},......}
按照從左到右,從上到下的順序,每個像素占三個byte。
如果把這個數據通過JNI傳給Java程序,然后再按照上述邏輯重新“組裝”成一幅圖像,問題就來了。
為了便于調試,我使用了Matlab來“組裝”并觀察這幅Raw圖像(height=13, width=17):
a=[34,123,90,34,122,

];
m=1;
for i=1:13
for j=1:17
for k=1:3
if a(m)<0
a(m)=a(m)+256;
end
d(i,j,k)=a(m);m=m+1;
end
end
end
figure,imshow(uint8(d));

典型的,對于一個三通道,顏色深度為256的圖像img,假設我們知道它的width,height,為了取得其RawData,可以定義一個數組data,并調用cvGetRawData()函數,將RawData存放到data中:
int raw_data_length = width*height*3;
byte* data= (byte *)malloc(raw_data_length * sizeof(byte));
cvGetRawData( img, (uchar**)&data, NULL, NULL );
byte* data= (byte *)malloc(raw_data_length * sizeof(byte));
cvGetRawData( img, (uchar**)&data, NULL, NULL );
那么,這個時候,data內部是如何組織的呢?按照一般的邏輯,它應該是這樣

按照從左到右,從上到下的順序,每個像素占三個byte。
如果把這個數據通過JNI傳給Java程序,然后再按照上述邏輯重新“組裝”成一幅圖像,問題就來了。
為了便于調試,我使用了Matlab來“組裝”并觀察這幅Raw圖像(height=13, width=17):





for i=1:13










應該是圖像RawData的Size,Step之類的錯誤。
最終我沒有找到具體錯在那里,但是用下面的代碼可以得到正確的數據。
// reconstruct image data
char *data;
int i, j, step;
CvSize size;
cvGetRawData( rstImg, (uchar**)&data, &step, &size );
step /= sizeof(data[0]);
int k = 0, offset = 0;
for ( i=0; i<size.height; i++, offset=i*step) {
for ( j=0; j<size.width; j++ ) {
result[k++] = data[offset+2];
result[k++] = data[offset+1];
result[k++] = data[offset];
offset += 3;
}
}
注意,Java里面的RGB圖像和OpenCV的通道順序正好是反過來的,即一個是RGB,一個是BGR。
char *data;
int i, j, step;
CvSize size;
cvGetRawData( rstImg, (uchar**)&data, &step, &size );
step /= sizeof(data[0]);
int k = 0, offset = 0;
for ( i=0; i<size.height; i++, offset=i*step) {
for ( j=0; j<size.width; j++ ) {
result[k++] = data[offset+2];
result[k++] = data[offset+1];
result[k++] = data[offset];
offset += 3;
}
}
至此,總算可以把OpenCV的圖像和Java的圖像對應起來了。至于如何在兩者之間傳遞圖像數據,請參見@todo:
posted on 2006-11-28 16:11 肥蟲 閱讀(2049) 評論(0) 編輯 收藏 所屬分類: Image Processing 、Java Language