CImg的图像内存内存获取

CImg是个简单方便的图像库,只有一个头文件和一些plugin文件,直接用就可以了,应用非常方便;

这里以位图举例子:如:


一:

#include "CImg.h"
using namespace cimg_library;

void showbmp()

{

CImg image;
image.load_bmp("t.bmp");
image.display();

}


二:

当然也可以获取图像的宽高等信息,包括可以获取图像像素指针;

如:

CImg image;

unsigned char * pix =  image.data();


三:

但是这里要注意:

1:CImg获取的图像宽度,而没有获取图像字节对齐后的宽度;


2:获取的像素指针与图像在内存中实际的排列方式不同;

我根据const CImg& _save_rgb(std::FILE *const file, const char *const filename) ;修改了一个可以获取与内存保持一致的获取方法:


unsigned char * get_CImgRgbPixBuf( CImg & image ) 
{
if ( image._width == 0 || image._height == 0 )
{
return 0;
}


const unsigned long wh = (unsigned long)( image._width * image._height );
unsigned char *const buffer = new unsigned char[3*wh], *nbuffer = buffer;


unsigned char * ptr1 = 0;
unsigned char * ptr2 = 0;
unsigned char * ptr3 = 0;


ptr1 = image.data(0,0,0,0),
ptr2 = image._spectrum>1?image.data(0,0,0,1):0,
ptr3 = image._spectrum>2?image.data(0,0,0,2):0;




switch (image._spectrum)
{
case 1 : 
{ // Scalar image
for (unsigned long k = 0; k{
const unsigned char val = (unsigned char)*(ptr1++);
*(nbuffer++) = val;
*(nbuffer++) = val;
*(nbuffer++) = val;
}
} break;
case 2 : 
{ // RG image
for (unsigned long k = 0; k{
*(nbuffer++) = (unsigned char)(*(ptr1++));
*(nbuffer++) = (unsigned char)(*(ptr2++));
*(nbuffer++) = 0;
}
} break;
default :
{ // RGB image
for (unsigned long k = 0; k{
*(nbuffer++) = (unsigned char)(*(ptr1++));
*(nbuffer++) = (unsigned char)(*(ptr2++));
*(nbuffer++) = (unsigned char)(*(ptr3++));
}
}
}


return buffer;
}


但是,这个函数依然有一些问题,因为没有考虑到图像的字节对齐,当然大部分情况是可以用的;



如果一定要考虑字节对齐的问题,可以参考:const CImg& _save_bmp(std::FILE *const file, const char *const filename) 这个函数的实现;

简单讲解一下这个函数:

(1):这个函数默认保存到是24位位图;

    const unsigned int      align        =  (4 - (3*_width)%4)%4; //计算位图字节对齐所每行需要的字节数;

    const unsigned int      buf_size  =  (3*_width + align)*height(); //获取像素实际需要的内存大小;

    ......



//获取相关像素内存指针;

      const T
        *ptr_r = data(0,_height-1,0,0),
        *ptr_g = (_spectrum>=2)?data(0,_height-1,0,1):0,
        *ptr_b = (_spectrum>=3)?data(0,_height-1,0,2):0;


//循环将像素写到文件中;

      default : {

        cimg_forY(*this,y) {  //高度;
          cimg_forX(*this,x) {   //每行;
            std::fputc((unsigned char)(*(ptr_b++)),nfile);
            std::fputc((unsigned char)(*(ptr_g++)),nfile);
            std::fputc((unsigned char)(*(ptr_r++)),nfile);
          }
          cimg::fwrite(align_buf,align,nfile); //字节对齐;
          ptr_r-=2*_width; ptr_g-=2*_width; ptr_b-=2*_width;
        }
      }


这个算法才是真正需要的获取内存像素的算法,所以之前的函数可以修改:


int get_CImgRgbPixBufLen( CImg & image )
{
const unsigned int
align = (4 - (3*image._width)%4)%4,
buf_size = (3*image._width + align)*image.height();


return buf_size;
}




unsigned char * get_CImgRgbPixBuf1( CImg & image ) 
{
const unsigned int
align = (4 - (3*image._width)%4)%4,
buf_size = (3*image._width + align)*image.height();


unsigned char * pixRgb = new unsigned char[buf_size];
unsigned char * pix = pixRgb;


const unsigned char
*ptr_r = image.data(0,image._height-1,0,0),
*ptr_g = (image._spectrum>=2)?image.data(0,image._height-1,0,1):0,
*ptr_b = (image._spectrum>=3)?image.data(0,image._height-1,0,2):0;




switch (image._spectrum) 
{
case 1 : 
{
} break;
case 2 :
{
} break;
default : 
{
for(int ny = 0; ny < image._height; ny++ )
{
for( int nx = 0; nx < image._width; nx++ ) 
{
*pix++ = *ptr_b++;
*pix++ = *ptr_g++;
*pix++ = *ptr_r++;
}


pix += align ;
ptr_r-=2*image._width; ptr_g-=2*image._width; ptr_b-=2*image._width;
}
}
}


return pixRgb;


}



当然,如果有人说,CImg库中有可以转换为OpenCV的Iplimage 结构的函数,可以更方便获取像素指针, 但是这就必须安装OpenCV了。


四:

不过这个库还是有一些优点可以应用:

如:跨平台,图片格式转换,尤其是支持YUV的格式;


五:

通常情况下,如果没有特别需求,可以用这个图像库,不过如果是对图像处理有严格要求,用OpenCV比较好。



你可能感兴趣的:(多媒体常识,编解码,OpenCV)