基于GDAL库图像读写——涉及(tif/tiff/bmp/jpg/png/gif等)多种格式图像的I/O
Posted nanke_yh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于GDAL库图像读写——涉及(tif/tiff/bmp/jpg/png/gif等)多种格式图像的I/O相关的知识,希望对你有一定的参考价值。
说来也是神奇,之所以会发这篇文章,还是因为在CSDN发文章中无法上传tif格式的图片造成的,如下。
转入文件夹下,并不显示tif图片,选择所有文件确认一副tiff图片,仍然提示上传错误。不知道CSDN开发人员为什么要做这样的限制,只想问一下有啥意义呢?
由于以前在图像处理过程中一直使用的GDAL读写图片接口都很好用,也就都没细究,每次输出图片路径带上tif拓展名,就都没啥事。这次不是限制了嘛,想着输出图像直接改成其他格式不就行了。直接保存的图片拓展名改成jpg等,发现保存出来的图片无法打开,图片查看失败,提示文件损坏。
于是让我重新研究了一下GDAL读写图像的函数接口,其中主要用到的是RasterIO()函数,这个可参考李民录老师的博文:
GDAL源码剖析(七)之GDAL RasterIO使用说明(续)_GDAL专栏-CSDN博客
GDAL源码剖析(七)之GDAL RasterIO使用说明_GDAL专栏-CSDN博客_gdal rasterio
这里都以灰度图像(单波段)读写函数来演示。
对于读函数图像的格式影像不大,都能直接读入到内存:
ImgTyp* OpenImage(const char *FilePath,int &width,int &height )
GDALAllRegister();//注册、读取图像
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");//使之支持中文路径
GDALDataset *poDataset = NULL;
poDataset = (GDALDataset*)GDALOpen(FilePath,GA_ReadOnly);
if(poDataset == NULL)
cout<<"无法打开影像!"<<endl;
GDALDestroyDriverManager();
//获取图像数据的参数
width = poDataset->GetRasterXSize();
height = poDataset->GetRasterYSize();
//int nRastercount = poDataset->GetRasterCount();
//开辟内存
ImgTyp *pImageData = new ImgTyp[width * height];
int bandList = 1;
poDataset->RasterIO(GF_Read,0,0,width,height,pImageData,width,height,(GDALDataType)sizeof(ImgTyp)/*GDT_Byte*/,1,&bandList,0,0,0);
//cout<<"单波段影像读入完成!"<<endl;
//关闭GDAL库相关驱动和释放内存
GDALClose(poDataset);
return pImageData;
对于写函数,原函数:
void WriteTif( ImgTyp* pImageData,char *savepath,int width,int height)
GDALAllRegister();
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");//使之支持中文路径
char *GType = NULL;
GType = findImageTypeGDAL(savepath);
// 创建结果存储图像
if ( GType == NULL )
cout << "没有指定存储图像的格式,默认为GTiff" << endl;
const char *format ="GTiff";
GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName( format );
GDALDataset* WriteDataSet = poDriver->Create( savepath, width, height, 1, (GDALDataType)sizeof(ImgTyp)/*GDT_Byte*/, NULL );
GDALRasterBand* pand = WriteDataSet->GetRasterBand(1);
pand->RasterIO( GF_Write, 0, 0, width, height, pImageData, width, height, (GDALDataType)sizeof(ImgTyp)/*GDT_Byte*/, 0, 0 );
GDALClose( WriteDataSet );
cout<<"单波段影像保存完成!"<<endl;
其中findImageTypeGDAL函数:
char* findImageTypeGDAL(char *pImgFileName)
char *Gtype = NULL;
char fileExtension[_MAX_PATH]=NULL;
strcpy(fileExtension,pImgFileName);
if ((strstr(fileExtension,".tif")!=NULL)) Gtype = "GTiff";
else if ((strstr(fileExtension,".tiff")!=NULL)) Gtype = "GTiff";
else if ((strstr(fileExtension,".jpg")!=NULL)) Gtype = "JPEG";
else if ((strstr(fileExtension,".bmp")!=NULL)) Gtype = "BMP";
else if ((strstr(fileExtension,".png")!=NULL)) Gtype = "PNG";
else if ((strstr(fileExtension,".gif")!=NULL)) Gtype = "GIF";
else Gtype = NULL;
//else Gtype = "GDALRaw";
return Gtype;
我们重新来review一下上面两个函数,看findImageTypeGDAL函数,是不是发现能够解析各种格式的图片是吧。然后看WriteTif函数,内部首先根据路径获得保存图片的拓展名GType ,判断之后发现重新定义了const char *format ="GTiff";并且后面图片保存方式也都是按照GTiff格式来的:GDALDriver *poDriver = GetGDALDriverManager()->GetDriverByName( format );与GType无关了。
那么问题来了,对于保存为jpg等类型的情况下,解析GType为“JPEG”,但还是直接按tiff格式输出,最后文件名直接拓展名为.jpg而已。如此,该图片保存出来就会出现文件损坏问题。
主要是因为:利用GDAL库函数创建图像时,一般会用到GDALDriver类Create()函数,但是Create()函数不支持JPEG、PNG等格式。
所以又要怎么去保存JPEG、PNG等格式呢?,虽然Create()函数不支持但是CreateCopy()支持这些格式,所以根据已有的图像数据,不能直接创建jpg、png格式的图像,而要借助GDAL的MEM内存文件,来创建他们。如是就有了下一面改写的全格式适应的图片写函数:
void WriteOutImg( ImgTyp* pImageData,char *savepath,int width,int height)
GDALAllRegister();
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");//使之支持中文路径
char *GType = NULL;
GType = findImageTypeGDAL(savepath);
GDALDriver *poDriver;
GDALDataset* WriteDataSet;
GDALRasterBand* pand;
CPLErr err;
if ( GType == NULL )
cout << "没有指定存储图像的格式,默认为GTiff" << endl;
GType = "GTiff";
if ( strcmp("BMP",GType) == 0 || strcmp("GTiff",GType) == 0)
poDriver = GetGDALDriverManager()->GetDriverByName( GType );
// 创建结果存储图像
WriteDataSet = poDriver->Create( savepath, width, height, 1, (GDALDataType)sizeof(ImgTyp)/*GDT_Byte*/, NULL );
pand = WriteDataSet->GetRasterBand(1);
err = pand->RasterIO( GF_Write, 0, 0, width, height, pImageData, width, height, (GDALDataType)sizeof(ImgTyp)/*GDT_Byte*/, 0, 0 );
if(err != CE_None)
printf("写图像数据失败!");
return ;
else
poDriver = GetGDALDriverManager()->GetDriverByName("MEM");
WriteDataSet = poDriver->Create("",width, height,1,(GDALDataType)sizeof(ImgTyp),NULL);
pand = WriteDataSet->GetRasterBand(1);
err = pand->RasterIO(GF_Write,0,0,width, height,pImageData,width, height,(GDALDataType)sizeof(ImgTyp),0, 0);
if(err != CE_None)
printf("写图像数据失败!");
return ;
//以创建复制的方式,生成jpg文件
GDALDriver *pDriverJPG = GetGDALDriverManager()->GetDriverByName(GType);
pDriverJPG->CreateCopy(savepath,WriteDataSet,TRUE,0,0,0); //创建jpg文件
GDALClose( WriteDataSet );
cout<<"单波段影像保存完成!"<<endl;
其中涉及的字符串比较呢,可参考
C语言中字符串之间的比较【char*】/【string】_nanke_yh的博客-CSDN博客
而上面借助GDAL的MEM内存文件来保存jpg,png等图片可参考:GDAL创建JPG格式图像_hong__fang的专栏-CSDN博客
最后通过上面的I/O接口,对spot.tif影像进行测试,分别输出不同格式的影像:
发现所有影像均保存正常,文件显示正常,且保存影像的色彩正常。如此基于GDAL多中格式的图像读写接口就完善了,后面做图像处理就可以放心使用这两个接口了。
以上是关于基于GDAL库图像读写——涉及(tif/tiff/bmp/jpg/png/gif等)多种格式图像的I/O的主要内容,如果未能解决你的问题,请参考以下文章
gdal学习笔记利用python 的gdal,以及相关库进行遥感图像处理(影像裁剪,辐射定标,大气校正,异常值去除)——以基于landsat8数据提取NDVI为例