Copy OpenCV IplImage or Mat into Freeimage FIBITMAP

2.1k views Asked by At

I need to exchange data between FreeImage (FIBITMAP) and OpenCV format (IplImage and/or Mat). I'm fine with getting data from a FIBITMAP into an IplImage or Mat since FreeImage gives you a function FreeImage_GetScanLine which you can set the OPenCV imageData ptr equal to.

However, I'm stuck on how to do the reverse, i.e. once I have an OpenCV image, how do I get its data into a FreeImage image?

3

There are 3 answers

3
Martin Beckett On BEST ANSWER

You have to be a little careful just copying the data pointer, a lot of image formats have padding to start each new line on eg a 4byte boundary.

If your image has a GetScanLine() function then it's probably safer to make an empty plImage*/cv::Mat and memcopy each row with the pointer returned from GetScanLine() and the .ptr() member of cv::MAt

cv::Mat &src        
int srcRowBytes = width  * src.elemSize();

for (int ih=0;ih<height;ih++) {
    memcpy(dest.pointer_to_row(ih),src.ptr(ih),srcRowBytes);
}
0
etarion On

Well, if you don't mind the copy, you can just create an IplImage*/cv::Mat header for the FIBITMAP and then copy (using the opencv function), like this:

cv::Mat src; // your source image
FIBITMAP whatever; // allocate space for your FIBITMAP here
cv::Mat wrapper(height, width, CV_8UC3, ptr_from_FIBITMAP, step);
src.copyTo(wrapper);
0
KiP On

Here is a more detailed code for the conversion. There are many image data types in either library, I tried supporting most common ones. This assumes you are passing a cv::Mat as the source. FreeImage has the view perspective of lower left!

/*  These are openCV types
#define CV_8U   0
#define CV_8S   1
#define CV_16U  2
#define CV_16S  3
#define CV_32S  4
#define CV_32F  5
#define CV_64F  6
*/

/*  these are FI types
FIT_UNKNOWN = 0,    // unknown type
FIT_BITMAP  = 1,    // standard image           : 1-, 4-, 8-, 16-, 24-, 32-bit
FIT_UINT16  = 2,    // array of unsigned short  : unsigned 16-bit
FIT_INT16   = 3,    // array of short           : signed 16-bit
FIT_UINT32  = 4,    // array of unsigned long   : unsigned 32-bit
FIT_INT32   = 5,    // array of long            : signed 32-bit
FIT_FLOAT   = 6,    // array of float           : 32-bit IEEE floating point
FIT_DOUBLE  = 7,    // array of double          : 64-bit IEEE floating point
FIT_COMPLEX = 8,    // array of FICOMPLEX       : 2 x 64-bit IEEE floating point
FIT_RGB16   = 9,    // 48-bit RGB image         : 3 x 16-bit
FIT_RGBA16  = 10,   // 64-bit RGBA image        : 4 x 16-bit
FIT_RGBF    = 11,   // 96-bit RGB float image   : 3 x 32-bit IEEE floating point
FIT_RGBAF   = 12    // 128-bit RGBA float image : 4 x 32-bit IEEE floating point

*/

if(_dib)  // get rid of the current dib. 
    FreeImage_Unload(_dib);


int width  = src.size().width;
int height = src.size().height;

switch(src.type())
{
case CV_8U  :{_dib = FreeImage_AllocateT(FIT_BITMAP,width, height, 8) ;}break;  // 8  bit grayscale
case CV_8UC3:{_dib = FreeImage_AllocateT(FIT_BITMAP,width, height, 24);}break;  // 24 bit RGB
case CV_16U :{_dib = FreeImage_AllocateT(FIT_UINT16,width, height, 16);}break;  // 16 bit grayscale
case CV_16S :{_dib = FreeImage_AllocateT(FIT_INT16 ,width, height, 16);}break;
case CV_32S :{_dib = FreeImage_AllocateT(FIT_INT32 ,width, height, 32);}break;
case CV_32F :{_dib = FreeImage_AllocateT(FIT_FLOAT ,width, height, 32);}break;
case CV_64F :{_dib = FreeImage_AllocateT(FIT_DOUBLE,width, height, 32);}break;
default:ASSERT(FALSE);
}

if(_dib==NULL)
    return FALSE;


int srcRowBytes = width  * src.elemSize();

for (int ih=0;ih<height;ih++) 
{
    BYTE* ptr2Line = FreeImage_GetScanLine(_dib,(height-1)-ih);
    memcpy(ptr2Line,src.ptr(ih),srcRowBytes);
}
_bHasChanged = TRUE;

return TRUE;