IplImage和char*相互轉換

      在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" );
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章