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

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

      

        说明:本文章转载自: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即可。

       关键代码如下:

       

[csharp]  view plain copy
  1. /// <summary>  
  2.        /// GDAL栅格转换为位图  
  3.        /// </summary>  
  4.        /// <param name="ds">GDAL Dataset</param>  
  5.        /// <param name="showRect">显示区域</param>  
  6.        /// <param name="bandlist">需要显示的波段列表</param>  
  7.        /// <returns>返回Bitmap对象</returns>  
  8.        public Bitmap GetImage(OSGeo.GDAL.Dataset ds, Rectangle showRect, int[] bandlist)  
  9.        {  
  10.            int imgWidth = ds.RasterXSize;   //影像宽  
  11.            int imgHeight = ds.RasterYSize;  //影像高  
  12.   
  13.            float ImgRatio = imgWidth / (float)imgHeight;  //影像宽高比  
  14.   
  15.            //获取显示控件大小  
  16.            int BoxWidth = showRect.Width;  
  17.            int BoxHeight = showRect.Height;  
  18.   
  19.            float BoxRatio = imgWidth / (float)imgHeight;  //显示控件宽高比  
  20.              
  21.            //计算实际显示区域大小,防止影像畸变显示  
  22.            int BufferWidth, BufferHeight;     
  23.            if (BoxRatio >= ImgRatio)  
  24.            {  
  25.                BufferHeight = BoxHeight;  
  26.                BufferWidth = (int)(BoxHeight * ImgRatio);  
  27.            }  
  28.            else  
  29.            {  
  30.                BufferWidth = BoxWidth;  
  31.                BufferHeight = (int)(BoxWidth/ImgRatio);  
  32.            }  
  33.   
  34.            //构建位图  
  35.            Bitmap bitmap = new Bitmap(BufferWidth, BufferHeight,  
  36.                                     System.Drawing.Imaging.PixelFormat.Format24bppRgb);  
  37.              
  38.            if (bandlist.Length==3)     //RGB显示  
  39.            {  
  40.                int[] r = new int[BufferWidth * BufferHeight];  
  41.                Band band1 = ds.GetRasterBand(bandlist[0]);  
  42.                band1.ReadRaster(0, 0, imgWidth, imgHeight, r, BufferWidth ,BufferHeight, 0, 0);  //读取图像到内存  
  43.   
  44.                //为了显示好看,进行最大最小值拉伸显示  
  45.                double[] maxandmin1 = { 0, 0 };  
  46.                band1.ComputeRasterMinMax(maxandmin1,0);  
  47.   
  48.                int[] g = new int[BufferWidth * BufferHeight];  
  49.                Band band2 = ds.GetRasterBand(bandlist[1]);  
  50.                band2.ReadRaster(0, 0, imgWidth, imgHeight, g, BufferWidth, BufferHeight, 0, 0);  
  51.   
  52.                double[] maxandmin2 = { 0, 0 };  
  53.                band2.ComputeRasterMinMax(maxandmin2, 0);  
  54.                  
  55.                int[] b = new int[BufferWidth * BufferHeight];  
  56.                Band band3 = ds.GetRasterBand(bandlist[2]);  
  57.                band3.ReadRaster(0, 0, imgWidth, imgHeight, b, BufferWidth, BufferHeight, 0, 0);  
  58.   
  59.                double[] maxandmin3 = { 0, 0 };  
  60.                band3.ComputeRasterMinMax(maxandmin3, 0);  
  61.   
  62.                int i, j;  
  63.                for (i = 0; i < BufferWidth; i++)  
  64.                {  
  65.                    for (j = 0; j < BufferHeight; j++)  
  66.                    {  
  67.                        int rVal=Convert.ToInt32(r[i + j * BufferWidth]);  
  68.                        rVal = (int)((rVal - maxandmin1[0]) / (maxandmin1[1] - maxandmin1[0]) * 255);  
  69.   
  70.                        int gVal=Convert.ToInt32(g[i + j * BufferWidth]);  
  71.                        gVal = (int)((gVal - maxandmin2[0]) / (maxandmin2[1] - maxandmin2[0]) * 255);  
  72.   
  73.                        int bVal=Convert.ToInt32(b[i + j * BufferWidth]);  
  74.                        bVal = (int)((bVal - maxandmin3[0]) / (maxandmin3[1] - maxandmin3[0]) * 255);  
  75.   
  76.                        Color newColor = Color.FromArgb(rVal, gVal, bVal);  
  77.                        bitmap.SetPixel(i, j, newColor);  
  78.                    }  
  79.                }  
  80.            }   
  81.            else               //灰度显示  
  82.            {  
  83.                int[] r = new int[BufferWidth * BufferHeight];  
  84.                Band band1 = ds.GetRasterBand(bandlist[0]);  
  85.                band1.ReadRaster(0, 0, imgWidth, imgHeight, r, BufferWidth, BufferHeight, 0, 0);  
  86.   
  87.                double[] maxandmin1 = { 0, 0 };  
  88.                band1.ComputeRasterMinMax(maxandmin1, 0);  
  89.                  
  90.                int i, j;  
  91.                for (i = 0; i < BufferWidth; i++)  
  92.                {  
  93.                    for (j = 0; j < BufferHeight; j++)  
  94.                    {  
  95.                        int rVal = Convert.ToInt32(r[i + j * BufferWidth]);  
  96.                        rVal = (int)((rVal - maxandmin1[0]) / (maxandmin1[1] - maxandmin1[0]) * 255);  
  97.   
  98.                        Color newColor = Color.FromArgb(rVal, rVal, rVal);  
  99.                        bitmap.SetPixel(i, j, newColor);  
  100.                    }  
  101.                }  
  102.            }  
  103.   
  104.            return bitmap;  
  105.        }  

 

3、  主函数调用

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

[csharp]  view plain copy
  1. private void ImageShow()  
  2.     {  
  3.         string filename="";  
  4.             OpenFileDialog dlg = new OpenFileDialog();  
  5.             dlg.Filter = "Tiff文件|*.tif|Erdas img文件|*.img|Bmp文件|*.bmp|jpeg文件|*.jpg|所有文件|*.*";  
  6.             if (dlg.ShowDialog() == DialogResult.OK)  
  7.             {  
  8.                 filename = dlg.FileName;  
  9.             }  
  10.   
  11.             if (filename == "")  
  12.             {  
  13.                 MessageBox.Show("影像路径不能为空");  
  14.                 return;  
  15.             }  
  16.         OSGeo.GDAL.Dataset ds= Gdal.Open(filename, Access.GA_ReadOnly);  
  17.         if(ds==null)  
  18.         {  
  19.         MessageBox.Show("影像打开失败");  
  20.         return;  
  21.         }  
  22.         Rectangle pictureRect = new Rectangle();  
  23.             pictureRect.X = 0;  
  24.             pictureRect.Y = 0;  
  25.             pictureRect.Width = this.pictureBox1.Width;  
  26.             pictureRect.Height = this.pictureBox1.Height;  
  27.               
  28.         int[] disband = {3,2,1};  
  29.               
  30.         Bitmap bitmap = GetImage(ds, pictureRect, disband);   //遥感影像构建位图  
  31.             pictureBox1.Image = bitmap;                   //将位图传递给PictureBox控件进行显示  
  32.               
  33.     }  




4、  结果展示

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



相关文章
|
4月前
|
传感器 定位技术 C++
基于C++的GDAL用空白栅格填充长时间序列遥感影像中的缺失图像
然后,定义需要处理的遥感影像路径列表,和识别数据缺失的逻辑。这里我们简化处理,假设已经知道哪一幅图像是缺失的,因此直接跳过识别步骤。
61 1
|
7月前
|
存储 编解码 API
基于GDAL命令行对遥感影像加以投影的方法
【2月更文挑战第3天】本文介绍基于gdal模块,在命令行中通过GDAL命令的方式(不是Python或者C++代码,就是gdal模块自身提供的命令行工具),对栅格遥感影像数据加以投影,即将原本的地理坐标系转为投影坐标系的方法~
212 5
基于GDAL命令行对遥感影像加以投影的方法
ArcMAP对遥感影像进行波段提取的3种方法
ArcMAP对遥感影像进行波段提取的3种方法
1078 0
|
7月前
|
机器学习/深度学习 定位技术 索引
Python读取栅格遥感影像并加以辐射校正后导出为Excel的一列数据
Python读取栅格遥感影像并加以辐射校正后导出为Excel的一列数据
|
7月前
|
数据安全/隐私保护 Sentinel Python
MODIS遥感影像数据Earthdata中批量下载多张图像方法
MODIS遥感影像数据Earthdata中批量下载多张图像方法
138 1
|
7月前
|
传感器 算法 定位技术
Python中gdal实现MODIS卫星遥感影像产品栅格数据读取处理与质量控制QC波段筛选掩膜
Python中gdal实现MODIS卫星遥感影像产品栅格数据读取处理与质量控制QC波段筛选掩膜
130 1
|
7月前
|
Web App开发
基于LAADS DAAC的MODIS遥感影像各产品数据批量下载多张图像方法
基于LAADS DAAC的MODIS遥感影像各产品数据批量下载多张图像方法
|
7月前
|
存储 传感器 定位技术
Landsat系列卫星遥感影像数据USGS中批量下载多张图像的方法
Landsat系列卫星遥感影像数据USGS中批量下载多张图像的方法
148 1
|
7月前
|
定位技术
ENVI软件实现栅格遥感影像基于像元的镶嵌拼接
ENVI软件实现栅格遥感影像基于像元的镶嵌拼接
|
7月前
|
定位技术 Python
Python中ArcPy基于矢量范围批量裁剪大量栅格遥感影像
Python中ArcPy基于矢量范围批量裁剪大量栅格遥感影像
168 1