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

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





for i=1:13










應(yīng)該是圖像RawData的Size,Step之類的錯誤。
最終我沒有找到具體錯在那里,但是用下面的代碼可以得到正確的數(shù)據(jù)。
// 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的圖像對應(yīng)起來了。至于如何在兩者之間傳遞圖像數(shù)據(jù),請參見@todo:
posted on 2006-11-28 16:11 肥蟲 閱讀(2048) 評論(0) 編輯 收藏 所屬分類: Image Processing 、Java Language