Review:
用gdal,感觉还不如直接用C++底层函数对遥感数据进行处理。因为gdal进行太多封装,如果你仅仅只是Geotif等格式进行处理,IO,遍历,转换,算法处理等操作,就别用gdal了。如果你想懒省事,那么这篇文章还是或许有些参考价值了。但是不推荐你这么做。

一.gdal进行数据操作

在安装好gdal后,即可调用gdal库中的函数。
(需要包含的头文件:gdal_priv.h)
1.打开数据集
使用gdal库进行数据(影像)操作的第一步就是打开一个数据集。对于“数据集”这个名词大家可能不会太习惯,但是对于一般的格式来说,一个“数据集”就是一个文件,比如一个TIFF文件就是一个以tiff为扩展名的文件。但是对于众多RS数据来说,一个数据集包含的绝对不仅仅是一个文件。对于很多RS数据,他们把一张图像分成数个图像文件,然后放在一个文件夹中,用一些额外的文件来组织它们之间的关系,形成一个“数据集”(有点难以理解,暂且放过)。下面我们由给定的文件路径文件名打开一个tiff(GeoTIFF)文件。(任何支持的格式,打开方式都是这样)

CString strFilePath;
StrFilePath=’d:/rsdata/2005_234.tif’;
GDALDataSet *poDataset; //GDAL数据集
GDALAllRegister();
poDataset = (GDALDataset *) GDALOpen(strFilePath, GA_ReadOnly ); 这样我们就打开了这个文件。通过数据集poDataset即可调用各功能函数,如:
GetRasterCount();//获取图像波段数;
GetRasterXSize();//获取图像宽度
GetRasterYSize();//获取图像高度
GetRasterBand();//获取图像某一波段
GetGeoTransform(double *p);//获取图像地理坐标信息长度为六的数组
RasterIO();//对图像数据进行缩放读和写
……

(更具体的API列表可以看这里)。

2.获取图像信息、读取图像

打开文件后,下面要做的就是获取文件的相关信息保存在相应变量中,将图像数据读入内存中,等待后续处理了。

2.1 获取基本信息
因为不同格式数据所包含的相关信息有所不同,一般情况下我们需要得到图像的高、宽、波段数、地理坐标信息,数据类型等。Gdal库中有相应的函数实现这些功能。下面的代码实现获取这些信息:

int nBandCount=poDataset->GetRasterCount();
int nImgSizeX=poDataset->GetRasterXSize();
int nImgSizeY=poDataset->GetRasterYSize();
double adfGeoTransform[6];
poDataset->GetGeoTransform( adfGeoTransform );
//如果图像不含地理坐标信息,默认返回值是:(0、1、0、0、0、1),表中第四列表示了带//有地理坐标信息的数据格式
// adfGeoTransform[0]是左上角像元的东坐标;
// adfGeoTransform[3]是左上角像元的北坐标;
// adfGeoTransform[1]是像元宽度;
// adfGeoTransform[5]是像元高度;
//图像其他点坐标计算公式:
//Xp = adfGeoTransform [0] + P*adfGeoTransform [1]+L*adfGeoTransform [2];
//Yp = adfGeoTransform [3] + P*adfGeoTransform [4] + L*adfGeoTransform [5];
//注:用GetGeoTransform()并不能十分合理的表示图像地理坐标,当影像范围很大时,这种坐标表示方法将不适用。

2.2 将图像数据按照要求读入内存
图像的读写是通过RasterIO()实现的。RasterIO()功能十分强大,它可以把图像上指定大小的矩形象素块以缩放的形式按指定的数据类型输出或输入到用户指定大小的缓冲区中。
原型:

CPLErr GDALDataset::RasterIO(
GDALRWFlag eRWFlag, //读写标记如果为GF_Read,则是将影像内容写入内存,如果
//为GF_Write,则是将内存中内容写入文件。
int nXOff, int nYOff, //相对于图像左上角顶点(从零开始)的行列偏移量
int nXSize, int nYSize, //要读写的块在x方向的象素个数和y方向的象素列数
void * pData, //指向目标缓冲区的指针,由用户分配
int nBufXSize, int nBufYSize,//目标块在x方向上和y方向上的大小
GDALDataType eBufType, //目标缓冲区的数据类型,原类型会自动转换为目标类型
int nBandCount, //要处理的波段数
int * panBandMap, //记录要操作的波段的索引(波段索引从1开始)的数组,若为空
//则数组中存放的是前nBandCount个波段的索引
int nPixelSpace, //X方向上两个相邻象素之间的字节偏移,默认为0,
//则列间的实际字节偏移由目标数据类型eBufType确定
int nLineSpace, //y方向上相邻两行之间的字节偏移, 默认为0,则行间的实际字节
//偏移为eBufType * nBufXSize
int nBandSpace //相邻两波段之间的字节偏移,默认为0,则意味着波段是顺序结构
//的,其间字节偏移为nLineSpace * nBufYSize
);

下面将通过实例演示其使用方法,实现的是将7波段图像中的第2 3 4波段按照3 4 2的顺序读入内存中,逐像素存储:

   int bandmap[7];
bandmap[0]=3;
bandmap[1]=4;
bandmap[2]=2;
Scanline=(nImagSizex*8+31)/32*4;
 BYTE pafScan=( BYTE )CPLMalloc(sizeof(byte) *nImgSizeX*nImgSizeY*3)
 poDataset->RasterIO( GF_Read, 0, 0,nImgSizeX,nImgSizeY, pafScan,
nImgSizeX,nImgSizeY,GDT_Byte,3,bandmap,3, Scanline*3,1 );

以这种方式读取之后,直接可构建位图进行显示。这里可以按照自己的需要进行其他方式读取。以上读取方式仅仅为了显示方便,如进行图像处理相关运算,则按波段全部读出会比较方便:
poDataset->RasterIO( GF_Read, 0, 0,nImgSizeX,nImgSizeY, pafScan,
nImgSizeX,nImgSizeY,GDT_Byte,bandcount,0,0,0,0);
之前开辟内存改为:
BYTE   pafScan=new byte[nImgSizeX*nImgSizeY*bandcount];

将图像数据读入内存后,即可通过指针pafScan对图像进行你想要进行的操作了。

3.另存图像
另存文件其实就是先创建一个新的文件,然后将数据写入新文件中。
使用gdal创建新文件有两种方式:Create()和CreateCopy();有些文件格式支持Create()函数(见第一页表格第三列),可以使用Create()直接创建此类格式的文件,而其他不支持Create()函数的图像格式,需要先创建tiff格式文件,然后复制生成目标格式文件。

CString strFilePath1;//输入图像文件路径名
CString strFilePath2;//另存为的tiff格式图像路径
CString strFilePath2; //另存为的jpeg格式图像路径
GDALDataset *poDataset1; //GDAL数据集
GDALDataset *poDataset2; //待创建的GDAL数据集
GDALDataset *poDataset2; //待创建的GDAL数据集
GDALDriver *poDriver; //驱动,用于创建新的文件
GDALAllRegister();
poDataset1 = (GDALDataset *) GDALOpen(strFilePath1, GA_ReadOnly );
// 打开文件
if( poDataset1 == NULL )
{
AfxMessageBox("文件打开失败!!!");
m_FileFlag=FALSE;
return;
}
//Create方式创建新的tiff文件:
nBandCount=poDataset1->GetRasterCount();
nImgSizeX=poDataset1->GetRasterXSize();
nImgSizeY=poDataset1->GetRasterYSize();
//获取影像相关信息 //创建新文件
Cstring fomat;
fomat="GTiff"
poDriver = GetGDALDriverManager()->GetDriverByName(fomat);
//设置文件类型,表格第二列为格式标识,保存为其他格通过改变fomat值即可 //获取格式类型
char **papszMetadata = poDriver->GetMetadata(); //根据文件路径文件名,图像宽,高,波段数,数据类型,文件类型,创建新的数据集
poDataset2=poDriver->Create(strFilePath2,nImgSizeX,nImgSizeY,nBandCount,GDT_Byte,papszMetadata);
//坐标赋值
double adfGeoTransform[6]={0,1,0,0,0,1};
poDataset2->SetGeoTransform(adfGeoTransform); //将原图像数据读出,进行相应处理后,写入新文件
BYTE *ppafScan= new BYTE [nImgSizeX * nImgSizeY *nBandCount];
poDataset1->RasterIO( GF_Read,0,0, nImgSizeX, nImgSizeY, ppafScan,
nImgSizeX, nImgSizeY, GDT_Byte,nBandCount,0,0, 0,0 );

//-------------『中间对图像进行处理运算』-------------------
.
//将图像数据写入新图像中
poDataset2->RasterIO(GF_Write, 0,0, nImgSizeX, nImgSizeY,
ppafScan,pafsizex,pafsizey, GDT_Byte,nBandCount,0,0, 0,0 ); delete poDataset2;
delete poDriver;
//图像另存完毕 CreateCopy方式创建jpeg格式文件:
接上面的过程,先不delete,(即已经完成用create方式先将运算完毕的图像创建为tiff格式)
fomat="Jpeg"
poDriver = GetGDALDriverManager()->GetDriverByName(fomat);
poDataset3=poDriver->CreateCopy(strFilePath3,poDataset2,1,papszMetadata,NULL,NULL);
delete poDataset3;
delete poDataset2;
delete podriver;

二.使用RasterIO()对大图像进行分块操作

RasterIO()函数能够对图像任意指定区域任意波段的数据按指定数据类型,指定排列方式读入内存和写入文件中,因此可以实现对大影像的分块读,运算,写操作。对于大图像处理,按照传统方法,首先要将图像所有数据读入内存中,进行相应操作后,再一次性将处理好的数据写入文件中,这样需要耗费很大内存,容易内存溢出,而且存续可执行行差。采用分块处理技术,一幅1G的影像,在整个数据处理过程中,可以只占用几十兆的内存,而且运算量不会增加。下面通过一个示例加以演示:
/所有波段分块处理示例

void CTestzwDoc::OnLowers()
{
Inoutput dlg; //获取文件路径的对话框类
if (dlg.DoModal()==IDCANCEL)
{
return;
}
CString strFilePath1(dlg.m_input);
CString strFilePath2(dlg.m_output);
GDALDataset *poDataset1; //GDAL数据集
GDALDataset *poDataset2; //GDAL数据集
GDALDriver *poDriver;
GDALAllRegister(); poDataset1 = (GDALDataset *) GDALOpen(strFilePath1, GA_ReadOnly );
if( poDataset1 == NULL )
{
AfxMessageBox("文件打开失败!!!");
m_FileFlag=FALSE;
return;
}
int BandCount=poDataset1->GetRasterCount();
int nImgSizeX=poDataset1->GetRasterXSize();
int nImgSizeY=poDataset1->GetRasterYSize(); //创建新文件
CString format;
format="Gtiff";
poDriver = GetGDALDriverManager()->GetDriverByName(format);
char ** papszMetadata = poDriver->GetMetadata();
poDataset2=poDriver->Create(strFilePath2,nImgSizeX,nImgSizeY,nBandCount,GDT_Byte,papszMetadata);
//设置图像坐标,缺少这一步,创建的图像用erdas打开将无法正常现实
poDataset2->SetGeoTransform(adfGeoTransform );
/////////////////////////////////////////////////////
//分块处理.将影像分成很多512*512大小的块,通过循环对每一块进行处理
int nxNum=(nImgSizeX-1)/512+1;//计算列方向上块数
int nyNum=(nImgSizeY-1)/512+1;//计算行方向块数
int pafsizex; //当前块宽度
int pafsizey; //当前块高度
BYTE * lp;
BYTE *ppafScan= new BYTE [512*512*nBandCount];
for (int nYI=0;nYI<nyNum;nYI++)
for (int nXI=0;nXI<nxNum;nXI++)
{
pafsizex=512;
pafsizey=512;
//行列末尾小块处理
if (nXI==nxNum-1)pafsizex=(nImgSizeX-1)%512+1;
if (nYI==nyNum-1)pafsizey=(nImgSizeY-1)%512+1;
//读取当前块数据
poDataset1->RasterIO( GF_Read, nXI*512, nYI*512,pafsizex,
pafsizey,ppafScan,pafsizex,pafsizey,GDT_Byte,BandCount,0,0,0,0);
//对当前块进行处理,边缘提取
for(int nnum=0;nnum<nBandCount;nnum++)
for (int i=0;i<pafsizey;i++)
for(int j=0;j<pafsizex;j++)
{
{
lp=ppafScan+nnum*pafsizex*pafsizey+i*pafsizex+j;
if(j==pafsizex-1&&i!=pafsizey-1)
*lp=abs(*lp-*(lp+pafsizex));
else if (i==pafsizey-1&&j==pafsizex-1)
*lp=0;
else if (i==pafsizey-1&&j!=pafsizex-1)
*lp=abs(*lp-*(lp+1));
else *lp=abs((*lp)-*(lp+1))+abs(*lp-*(lp+pafsizex));
//边缘处理是难点
if (*lp<15)
*lpp=0;
else if(15<=*lpp<30)
*lpp=128;
else if(*lpp>=30)
*lpp=255;
}
}
//将当前块数据写入新图像相应位置
poDataset2->RasterIO(GF_Write,nXI*512,nYI*512,pafsizex,pafsizey,ppafScan,pafsizex,pafsizey, GDT_Byte,nBandCount,0,0, 0,0 );
}
delete []ppafScan;
//写操作完成后必须释放,不然写入操作不成功
delete poDataset2;
delete poDataset1;
delete poDriver;
delete dlg;
}

在前面一篇介绍gdal库读取和存储图像的文章中,有很多不足之处,个人觉得其精华在于在内存中创建位图,并进行快速显示部分。
两个相邻象素之间的字节偏移,则如按波段存储,则置为0
行偏移量,如按波段存储,则置为0
置1逐像素存储,置0按波段存储

gdal读写图像分块处理的更多相关文章

  1. gdal读写图像分块处理(精华版)

    一.gdal进行数据操作在安装好gdal后,即可调用gdal库中的函数.(需要包含的头文件:gdal_priv.h)1.打开数据集使用gdal库进行数据(影像)操作的第一步就是打开一个数据集.对于“数 ...

  2. GDAL关于读写图像的简明总结

    读写影像可以说是图像处理最基础的一步.关于使用GDAL读写影像,平时也在网上查了很多资料,就想结合自己的使用心得,做做简单的总结. 在这里写一个例子:裁剪lena图像的某部分内容,将其放入到新创建的. ...

  3. ArcEngine和GDAL读写栅格数据机制对比(一)

    最近应用AE开发插值和栅格转等值线的程序,涉及到栅格读写的有关内容.联想到ArcGIS利用了GDAL的某些东西,从AE的OMD中也发现RasterDataset和RasterBand这些命名和GDAL ...

  4. Java 读写图像

    Java中进行图像I/O(即读图片和写图片,不涉及到复杂图像处理)有三个方法:1. Java Image I/O API,支持常见图片,从Java 2 version 1.4.0开始就内置了.主页:h ...

  5. matlab处理:批处理图像分块

    有一个图像分块的代码,可以直接将一幅图像分为5*5的小块,代码如下: %[FileName,PathName] = uigetfile('*.*','Select the image'); Im=im ...

  6. 使用方向变换(directional transform)图像分块压缩感知

    论文的思路是先介绍分块压缩感知BCS,然后介绍使用投影和硬阈值方法的迭代投影方法PL,接着将PL与维纳滤波器结合形成SPL(平滑PL),并且介绍了稀疏表示的几种基,提出了两种效果较好的稀疏基:CT与D ...

  7. 关于GDAL读写Shp乱码的问题总结

    目录 1. 正文 1.1. shp文件本身的编码的问题 1.2. 设置读取的编码方式 1.2.1. GDAL设置 1.2.2. 解码方式 1.2.3. 其他 2. 参考 1. 正文 最近在使用GDAL ...

  8. GDAL创建图像提示Driver xxx does not support XXX creation option的原因

    经常在群里有人问,创建图像的时候为什么老是提示下面的信息. CPLError: Driver GTiff does not support DCAP_CREATE creation option Wa ...

  9. matlab学习笔记,图像分块

    clc; clear all; close all; I = imread('E:\matlab\files-images\tomsen512.jpg'); rs = size(I, 1);% 行数c ...

随机推荐

  1. vue组件递归的一些理解

    自己做个小项目练手,需要用到组件递归,网上查了一些资料,每个代码片段都认识,但是连起来,就一团浆糊. 既然人傻就多思考吧.不明白的点有以下: 1.组件怎么自己调用自己,函数的递归是就是在functio ...

  2. PHP 数组转字符串,字符串转数组

    explode将字符串分割为数组: $str = explode( ',',$str); 第一个参数为字符串的分界符,例如1,2,3,4. 第二个是需要分割的数组 分割后就是 array( 1 , 2 ...

  3. POJ-2785 Values whose Sum is 0 Hash表

    题目链接:https://cn.vjudge.net/problem/POJ-2785 题意 给出四组数,每组有n个数 现从每组数中取一个数作为a,b,c,d 问有几组这样的a+b+c+d=0 思路 ...

  4. Linux 常用命令:系统状态篇

    前言 Linux常用命令中,有些命令可以用于查看系统的状态,通过了解系统当前的状态,能够帮助我们更好地维护系统或定位问题.本文就简单介绍一下这些命令. 1. 查看系统运行时间--uptime 有时候我 ...

  5. PKU 2288 Islands and Bridges 状态dp

    题意: 给你一张地图,上面有一些岛和桥.你要求出最大的三角哈密顿路径,以及他们的数量. 哈密顿路:一条经过所有岛的路径,每个岛只经过一次. 最大三角哈密顿路:满足价值最大的哈密顿路. 价值计算分为以下 ...

  6. CSU 1364 Interview RMQ

    题意: 瑶瑶有一家有一家公司,最近他想招m个人.因为他的公司是如此的出名,所以有n个人来参加面试.然而,瑶瑶是如此忙,以至于没有时间来亲自面试他们.所以他准备选择m场面试来测试他们. 瑶瑶决定这样来安 ...

  7. CMSIS-RTOS 时间管理之时间延迟Time Delay

    时间管理 Time Management 此RTOS除了可以把你的应用代码作为线程运行,它还可以提供一些时间服务功能,使用这些功能你就可以访问RTOS的一些系统调用. 时间延迟Time Delay 在 ...

  8. Gradle编译spring3.x报错找不到itextpdf4.2.2解决方案

    google搜到一篇文章:http://www.bdtool.net/blog_356.html 试了文章里的两个方法,方法一不行,方法二有点搞头,但是还有些错.试着试着,突然成功了~ 我是这么做的 ...

  9. ArcGIS api for javascript——显示一个信息窗口

    描述 这个示例展示了在用户单击地图时如何在InfoWindow中显示信息.信息窗口是一个dijit (Dojo widget).信息窗口能够包含文本,字符,图片和任何通过HTML表示的事物.这个例子在 ...

  10. POJ 1035-Spell checker(字符串)

    题目地址:POJ 1035 题意:输入一部字典.输入若干单词. 若某个单词能在字典中找到,则输出corret.若某个单词能通过 变换 或 删除 或 加入一个字符后.在字典中找得到.则输出这些单词.输出 ...