GDAL 读写图片

使用GDAL打开和保存常见格式图像(代码)

https://blog.csdn.net/godenlove007/article/details/8864763


习惯了使用OpenCV的cvLoadImage函数和imread函数打开图像,但是貌似老师不喜欢opencv,实验室也用惯了GDAL,于是乎,就搜集各种资源,整理了使用GDAL读写图像的代码。

1.使用GDAL打开常见格式图像,并且保存到一维数组中
首先,需要判定图像后缀名,因为GDAL使用不同的驱动器打开对应的图像格式文件,笔者写了个支持JPG、BMP、PNG、GIF、TIFF格式判断的函数。注意,GDAL实际上可以说是个万能的图像格式转换库了,支持几十种图像格式,但是我们一般人常用的也就这么几种。

调用GDAL驱动器,打开图像,送进内存数组。
/******************************************************************************
函数名:
    readImageGDAL
功能:
    读取图像
参数:
    unsigned char **pImageData - 指向图像数据指针的指针,将由new操作符动态创建,需要在函数外部由调用者使用delete[]销毁,否则内存泄露
    int &width,int &height     - 图像宽度、高度,由于是引用,可以作为返回值。
    nChannels                  - 图像通道,可选值为1或3。1代表灰度图像,3代表RGB图像,-1表示按照图像自身通道数目读取。
    const char *filePath       - 图像文件路径名称
说明:******************************************************************************/
bool readImageGDAL(unsigned char **pImageData,int &width,int &height,int &nChannels, const char *filePath)
{
    GDALAllRegister();
    GDALDataset *poDataset = NULL;
    poDataset=(GDALDataset*) GDALOpen(filePath,GA_ReadOnly);    
    if(poDataset == NULL)
    {
        GDALClose(poDataset);
        return false;
    }
    width = poDataset->GetRasterXSize();
    height = poDataset->GetRasterYSize();
    GDALRasterBand* pBand;
    int i = 0;
    int nRastercount = poDataset->GetRasterCount();
    if (nRastercount == 1) //只有1个通道,则为灰度图像
    {
        nChannels = 1;
        pBand = poDataset->GetRasterBand(1); 
        *pImageData = new unsigned char[width * height];
        pBand->RasterIO(GF_Read,
                        0,0,            //nXOff,nYOff:从左上角坐标point(nXOff,nYOff)处读取图像数据
                        width,height,    //nXSize,nXSize:要读取的图像数据尺寸,注意可以不是band的实际尺寸,这样就是读取roi区域数据
                        *pImageData,    //pData:读取的数据即将存储的目的地址。
                        width,height,    //nBufXSize,nBufYSize:目的地址处图像的尺寸,如果与roi尺寸不一致,则缩放。
                        GDT_Byte,        //eBufType:读取图像后,将要存储为的类型
                        0,                //nPixelSpace:控制同一行相邻像素间隔,0代表使用目的数据类型大小
                        0);                //nLineSpace:控制相邻行的行间隔,0代表使用[目的数据类型大小 * nXsize]
        GDALClose(poDataset);
        return true;
    }
    else if ( nRastercount == 3 && (nChannels == 3 || nChannels < 0) ) //有3个通道,并且输出为RGB图像
    {        
        nChannels = 3;
        *pImageData = new unsigned char[nRastercount * width * height];        
        for (i = 1; i <= nRastercount; ++ i)
        {
            //GDAL内band存储顺序为RGB,需要转换为我们一般的BGR存储,即低地址->高地址为:B G R
            unsigned char *pImageOffset = *pImageData + i - 1;
            GDALRasterBand* pBand = poDataset->GetRasterBand(nRastercount-i+1);
            
            pBand->RasterIO(
                GF_Read,
                0,0,            
                width,height,    
                pImageOffset,    
                width,height,    
                GDT_Byte,        
                3,                
                0);                
        }
        GDALClose(poDataset);
        return true;
    }
    else if ( nRastercount == 3 && nChannels == 1 ) //有3个通道,但是要求输出灰度图像
    {
        unsigned char **img = new unsigned char*[nRastercount];
        for (i = 0; i < nRastercount; i++)
        {
            img[i] = new unsigned char[width * height];
        }
        for (i = 1; i <= nRastercount; ++ i)
        {
            //GDAL内band存储顺序为RGB,需要转换为我们一般的BGR存储,即低地址->高地址为:B G R
            pBand = poDataset->GetRasterBand(nRastercount-i+1); 
            pBand->RasterIO(GF_Read,
                            0,0,
                            width,height,
                            img[i-1],
                            width,height,
                            GDT_Byte,
                            0,
                            0);
        }
        GDALClose(poDataset);
        *pImageData = new unsigned char[width*height];
        for (int r = 0; r < height; ++ r)
        {
            for (int c = 0; c < width; ++ c)
            {
                int t = (r*width+c);
                //r g b分量依次占:0.299 0.587 0.144,可简化为3:6:1
                //img[1.2.3]依次对应BGR
                (*pImageData)[t] = (img[2][t]*3 + img[1][t]*6 + img[0][t] + 5)/10;
            }
        }
    
        for (i = 0; i < nRastercount; ++ i)
        {
            delete [] img[i];
        }
        delete []img; img = NULL;
        return true;
    }
    else 
    {
        return false;
    }
}

以上代码是比较长,不过实现的功能适合cvLoadImage函数功能差不多的。特别是nChannels参数,如果在输入中指定为1,则不管图像文件时彩色还是灰度图像,都会转换为成为灰度图像存储在数组中,如果指定为3,则只有图像时彩色图像时,才会真的存成3通道图像。如果指定为负值,则按照图像的实际通道数目读取。
另外,注意一点,这个图像只读上述各种格式的灰度图像和3通道图像,其它的通道数目不支持。

2.保存图像到文件中
2.1根据文件后缀名判断图像格式。
函数代码如下:

char* findImageTypeGDAL( char *pDstImgFileName)
{
    char *dstExtension = strlwr(strrchr(pDstImgFileName,'.') + 1);
    char *Gtype = NULL;
    if        (0 == strcmp(dstExtension,"bmp")) Gtype = "BMP";
    else if (0 == strcmp(dstExtension,"jpg")) Gtype = "JPEG";
    else if (0 == strcmp(dstExtension,"png")) Gtype = "PNG";
    else if (0 == strcmp(dstExtension,"tif")) Gtype = "GTiff";
    else if (0 == strcmp(dstExtension,"gif")) Gtype = "GIF";
    else Gtype = NULL;
 
    return Gtype;
}
呵呵,太弱智了。
2.2保存图像代码
bool WriteImageGDAL(const char* pDstImgFileName,bool *pImageData,int width,int height,int nChannels)
{
    assert ( !(pDstImgFileName == NULL || pImageData == NULL || width <1 || height < 1 || nChannels < 1));
 
    GDALAllRegister();
    char *GType = NULL;
    GType = findImageTypeGDAL(pDstImgFileName);
    if (GType == NULL)    { return false; }
 
    GDALDriver *pMemDriver = NULL;
    pMemDriver = GetGDALDriverManager()->GetDriverByName("MEM");
    if( pMemDriver == NULL ) { return false; }
 
    GDALDataset * pMemDataSet = pMemDriver->Create("",width,height,nChannels,GDT_Byte,NULL);
    GDALRasterBand *pBand = NULL;
    int nLineCount = width * nChannels;
    unsigned char *ptr1 = (unsigned char *)pImageData;
    for (int i = 1; i <= nChannels; i++)
    {
        pBand = pMemDataSet->GetRasterBand(nChannels-i+1);
        pBand->RasterIO(GF_Write, 
                        0, 
                        0, 
                        width, 
                        height, 
                        ptr1+i-1 , 
                        width, 
                        height, 
                        GDT_Byte, 
                        nChannels, 
                        nLineCount); 
    }
 
    GDALDriver *pDstDriver = NULL;
    pDstDriver = (GDALDriver *)GDALGetDriverByName(GType);
    if (pDstDriver == NULL) { return false; }
    
    pDstDriver->CreateCopy(pDstImgFileName,pMemDataSet,FALSE, NULL, NULL, NULL);
    
    GDALClose(pMemDataSet); 
 
    return true; 
}
保存的结果文件格式,通过其后缀名给出。
3.补充说明
调用的GDAL库可在网上下载,在上述代码前部加入以下包含命令:
#include &quot;gdal.h&quot;
#include &quot;gdal_priv.h&quot;
#pragma comment(lib,&quot;gdal_i.lib&quot;)</pre>
其中,gdal_i.lib是GDAL库的导出库文件,另外还需要制定对应的dll文件的path路径。

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值