在OpenCV裏邊,widthStep必須是4的倍數,從而實現字節對齊,有利於提高運算速度。如果8U單通道圖像寬度爲3,那麼widthStep是 4,加一個字節補齊。這個圖像的一行需要4個字節,只使用前3個,最後一個空着。也就是一個寬3高3的圖像的imageData數據大小爲4*3=12字 節。
空着的那個像素並不是無效的,它仍然可以被操作:
IplImage* image = cvCreateImage(cvSize(15, 15), 8, 1);
memcpy(image->imageData, data, 15*15);
在cvCreateImage的時候,OpenCV爲實現字節對齊,使得每行數據實際有16個字節(多出一個),在使用memcpy的過程 中,這些多出的字節就把對應的數據給“喫”了,因爲這些數據在cvShowImage的時候並不會顯示出來,這樣,第二行就少一個字節,第三行少兩個字 節,……,這樣會造成整個圖像偏向左下角!
此時,應該這樣Copy:
for(int i = 0; i<15; i++)...{
memcpy(image->imageData + image->widthStep*i, data + 15*i, 15);
}
IplImage和單字節char*之間相互轉換的正確、簡潔的方法:
已知 IplImage* image 和 char* data
從 IplImage 到 char* :
data = image->imageData //對齊的圖像數據
或
data = image->imageDataOrigin //未對齊的原始圖像數據
從 char* 到 IplImage :
image = cvCreateImageHeader(cvSize(width,height), depth, channels);
cvSetData(image, data, step);
step指定IplImage圖像每行佔的字節數。需要注意是,在釋放空間時不能直接使用cvReleaseImage,而需cvReleaseImageHeader,然後再delete data。
cvSetData code from opencv2.3.1(now opencv2.4.3 is out . As usual, the packages are available at SourceForge (http://sourceforge.net/projects/opencvlibrary), or alternatively you can download the source code from https://github.com/Itseez/opencv/tree/2.4):
// Assigns external data to array
CV_IMPL void
cvSetData( CvArr* arr, void* data, int step )
{
int pix_size, min_step;
if( CV_IS_MAT_HDR(arr) || CV_IS_MATND_HDR(arr) )
cvReleaseData( arr );
if( CV_IS_MAT_HDR( arr ))
{
CvMat* mat = (CvMat*)arr;
int type = CV_MAT_TYPE(mat->type);
pix_size = CV_ELEM_SIZE(type);
min_step = mat->cols*pix_size;
if( step != CV_AUTOSTEP && step != 0 )
{
if( step < min_step && data != 0 )
CV_Error( CV_BadStep, "" );
mat->step = step;
}
else
mat->step = min_step;
mat->data.ptr = (uchar*)data;
mat->type = CV_MAT_MAGIC_VAL | type |
(mat->rows == 1 || mat->step == min_step ? CV_MAT_CONT_FLAG : 0);
icvCheckHuge( mat );
}
else if( CV_IS_IMAGE_HDR( arr ))
{
IplImage* img = (IplImage*)arr;
pix_size = ((img->depth & 255) >> 3)*img->nChannels;
min_step = img->width*pix_size;
if( step != CV_AUTOSTEP && img->height > 1 )
{
if( step < min_step && data != 0 )
CV_Error( CV_BadStep, "" );
img->widthStep = step;
}
else
{
img->widthStep = min_step;
}
img->imageSize = img->widthStep * img->height;
img->imageData = img->imageDataOrigin = (char*)data;
if( (((int)(size_t)data | step) & 7) == 0 &&
cvAlign(img->width * pix_size, 8) == step )
img->align = 8;
else
img->align = 4;
}
else if( CV_IS_MATND_HDR( arr ))
{
CvMatND* mat = (CvMatND*)arr;
int i;
int64 cur_step;
if( step != CV_AUTOSTEP )
CV_Error( CV_BadStep,
"For multidimensional array only CV_AUTOSTEP is allowed here" );
mat->data.ptr = (uchar*)data;
cur_step = CV_ELEM_SIZE(mat->type);
for( i = mat->dims - 1; i >= 0; i-- )
{
if( cur_step > INT_MAX )
CV_Error( CV_StsOutOfRange, "The array is too big" );
mat->dim[i].step = (int)cur_step;
cur_step *= mat->dim[i].size;
}
}
else
CV_Error( CV_StsBadArg, "unrecognized or unsupported array type" );
}