您的位置:首页 > 编程语言 > C#

基于GDAL的遥感影像显示(C#版) .

2013-08-01 16:27 417 查看
原文地址:http://blog.csdn.net/rsyaoxin/article/details/9220735   

 

 接触GDAL有四五年多时间了,平时都是在C++下使用,最近需要在C#下调用GDAL,所以就开始学习了下,相比C++调用,C#下使用GDAL做图像处理的效率有点低,但是其简单易学,适合菜鸟上手,现把自己刚学到的心得跟大伙分享下,以遥感影像的显示为例。

1、  程序环境搭建

        首先,需要编译GDAL库的源代码。
       GDAL是一个非常强悍的遥感数据格式解析库,支持多种遥感数据格式的读写,而且还有一些算法实现。然而,它只是一个开源库,并不是一个单独的软件,而是C++写的源代码,需要编译成动态链接库后才能为我们程序调用,如果需要在C#/.Net环境下调用,还需特别编译C#版的DLL。关于编译的方法网上很多教程,我就不介绍了,具体编译步骤可以参照民录大哥的博客:http://blog.csdn.net/liminlu0314/article/details/6937194

      如果很难编译成功,需要编译后的版本,可以留下邮箱,或者给我发邮件RSyaoxin@163.com。

      编译完成后,我们会得到9个DLL文件(以GDAL1.10版为例):gdal110.dll、gdal_csharp.dll、gdal_wrap.dll、gdalconst_csharp.dll、gdalconst_wrap.dll、ogr_csharp.dll、ogr_wrap.dll、osr_csharp.dll、osr_wrap.dll。

注意:需要强调的一点是,如果编译GDAL时添加了额外的依赖库,需要将其动态链接库一并拷贝过来。比如,我编译GDAL库时就添加了HDF4、HDF5、JPEG2000、NetCDF、Proj4等文件格式支持,那么调用的时候就需要将hd425m.dll等拷贝到同上面几个DLL一起。

         其次,C#下的环境配置。

        我们首先建立一个Windows窗体应用程序,将上面得到的9个DLL文件拷贝到项目所在的文件夹,然后在解决方案面板下找到引用项,右键添加引用,选择gdal_csharp.dll将它添加进来,这样就可以在C#调用GDAL函数了。

         再次,初始化GDAL环境。具体做法是:

        using  OSGeo.GDAL;
        将上面这一句添加到namespace这一行前面。
        然后在构造函数或者Form_Load函数中添加下面两行:
        OSGeo.GDAL.Gdal.AllRegister();
        OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8","YES");
        说明:第一行是注册所有的格式驱动,第二行是支持中文路径和名称,由于GDAL默认不支持中文路径,所以在编译的时候会修改源码让它支持中文路径,C++代码就可以直接支持了,但是会发现C#版还是会不支持,所以需要加上第二句。
       这样开发环境就搭建好了,可以直接调用GDAL函数进行图像处理了。

2、  关键代码

         C#下图像的显示方法有多种,最简单的方法就是构建位图。我们可以把GDAL下的Dataset转换为Bitmap供C#调用。在C#里面调用GDAL读取栅格数据的主要函数是ReadRaster,它相当于C++下的RasterIO函数,其有多重形式:

 

public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, byte[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, byte[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, short[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, short[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, int[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, int[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, float[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, float[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, double[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, double[] buffer,
int buf_xSize, int buf_ySize, int pixelSpace, int lineSpace)
public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, IntPtr buffer, i
nt buf_xSize, int buf_ySize, DataType buf_type, int pixelSpace, int lineSpace)
public CPLErr WriteRaster(int xOff, int yOff, int xSize, int ySize, IntPtr buffer,
int buf_xSize, int buf_ySize, DataType buf_type, int pixelSpace, int lineSpace)


这里面,xOff和yOff是指偏移量,即从影像的左上角起始坐标(xOff,yOff)开始读取数据。xSize和ySize是指读取图像数据的行列数,即宽度和高度,单位都是像素。Buffer是图像数据缓存。buf_xSize和buf_ySize是缓存区的大小,它们须与buffer申请的大小保持一致,通过这两个参数可以控制缩放,如果它们小于xSize和ySize就是将原图缩小,反之如果它们大于xSize和ySize就是将原图放大。pixelSpace和lineSpace一般默认取0即可。

       关键代码如下:

 

/// <summary>
/// GDAL栅格转换为位图
/// </summary>
/// <param name="ds">GDAL Dataset</param>
/// <param name="showRect">显示区域</param>
/// <param name="bandlist">需要显示的波段列表</param>
/// <returns>返回Bitmap对象</returns>
public Bitmap GetImage(OSGeo.GDAL.Dataset ds, Rectangle showRect, int[] bandlist)
{
int imgWidth = ds.RasterXSize;   //影像宽
int imgHeight = ds.RasterYSize;  //影像高

float ImgRatio = imgWidth / (float)imgHeight;  //影像宽高比

//获取显示控件大小
int BoxWidth = showRect.Width;
int BoxHeight = showRect.Height;

float BoxRatio = imgWidth / (float)imgHeight;  //显示控件宽高比

//计算实际显示区域大小,防止影像畸变显示
int BufferWidth, BufferHeight;
if (BoxRatio >= ImgRatio)
{
BufferHeight = BoxHeight;
BufferWidth = (int)(BoxHeight * ImgRatio);
}
else
{
BufferWidth = BoxWidth;
BufferHeight = (int)(BoxWidth/ImgRatio);
}

//构建位图
Bitmap bitmap = new Bitmap(BufferWidth, BufferHeight,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);

if (bandlist.Length==3)     //RGB显示
{
int[] r = new int[BufferWidth * BufferHeight];
Band band1 = ds.GetRasterBand(bandlist[0]);
band1.ReadRaster(0, 0, imgWidth, imgHeight, r, BufferWidth ,BufferHeight, 0, 0);  //读取图像到内存

//为了显示好看,进行最大最小值拉伸显示
double[] maxandmin1 = { 0, 0 };
band1.ComputeRasterMinMax(maxandmin1,0);

int[] g = new int[BufferWidth * BufferHeight];
Band band2 = ds.GetRasterBand(bandlist[1]);
band2.ReadRaster(0, 0, imgWidth, imgHeight, g, BufferWidth, BufferHeight, 0, 0);

double[] maxandmin2 = { 0, 0 };
band2.ComputeRasterMinMax(maxandmin2, 0);

int[] b = new int[BufferWidth * BufferHeight];
Band band3 = ds.GetRasterBand(bandlist[2]);
band3.ReadRaster(0, 0, imgWidth, imgHeight, b, BufferWidth, BufferHeight, 0, 0);

double[] maxandmin3 = { 0, 0 };
band3.ComputeRasterMinMax(maxandmin3, 0);

int i, j;
for (i = 0; i < BufferWidth; i++)
{
for (j = 0; j < BufferHeight; j++)
{
int rVal=Convert.ToInt32(r[i + j * BufferWidth]);
rVal = (int)((rVal - maxandmin1[0]) / (maxandmin1[1] - maxandmin1[0]) * 255);

int gVal=Convert.ToInt32(g[i + j * BufferWidth]);
gVal = (int)((gVal - maxandmin2[0]) / (maxandmin2[1] - maxandmin2[0]) * 255);

int bVal=Convert.ToInt32(b[i + j * BufferWidth]);
bVal = (int)((bVal - maxandmin3[0]) / (maxandmin3[1] - maxandmin3[0]) * 255);

Color newColor = Color.FromArgb(rVal, gVal, bVal);
bitmap.SetPixel(i, j, newColor);
}
}
}
else               //灰度显示
{
int[] r = new int[BufferWidth * BufferHeight];
Band band1 = ds.GetRasterBand(bandlist[0]);
band1.ReadRaster(0, 0, imgWidth, imgHeight, r, BufferWidth, BufferHeight, 0, 0);

double[] maxandmin1 = { 0, 0 };
band1.ComputeRasterMinMax(maxandmin1, 0);

int i, j;
for (i = 0; i < BufferWidth; i++)
{
for (j = 0; j < BufferHeight; j++)
{
int rVal = Convert.ToInt32(r[i + j * BufferWidth]);
rVal = (int)((rVal - maxandmin1[0]) / (maxandmin1[1] - maxandmin1[0]) * 255);

Color newColor = Color.FromArgb(rVal, rVal, rVal);
bitmap.SetPixel(i, j, newColor);
}
}
}

return bitmap;
}


 

3、  主函数调用

  得到Bitmap,我们就可以在程序中调用它了。我们可以在窗体上加一个PictureBox控件来显示图像,其name设为pictureBox1。主要调用代码如下:

private void ImageShow()
{
string filename="";
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Tiff文件|*.tif|Erdas img文件|*.img|Bmp文件|*.bmp|jpeg文件|*.jpg|所有文件|*.*";
if (dlg.ShowDialog() == DialogResult.OK)
{
filename = dlg.FileName;
}

if (filename == "")
{
MessageBox.Show("影像路径不能为空");
return;
}
OSGeo.GDAL.Dataset ds= Gdal.Open(filename, Access.GA_ReadOnly);
if(ds==null)
{
MessageBox.Show("影像打开失败");
return;
}
Rectangle pictureRect = new Rectangle();
pictureRect.X = 0;
pictureRect.Y = 0;
pictureRect.Width = this.pictureBox1.Width;
pictureRect.Height = this.pictureBox1.Height;

int[] disband = {3,2,1};

Bitmap bitmap = GetImage(ds, pictureRect, disband);   //遥感影像构建位图
pictureBox1.Image = bitmap;                   //将位图传递给PictureBox控件进行显示

}


 

4、  结果展示

    这样我们就可以很容易地显示遥感影像了。







    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: