1. 程式人生 > >基於GDAL的遙感影像顯示(C#版)

基於GDAL的遙感影像顯示(C#版)

        說明:本文章轉載自: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

      如果很難編譯成功,需要編譯後的版本,可以留下郵箱,或者給我發郵件[email protected]

      編譯完成後,我們會得到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即可。

       關鍵程式碼如下:

  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.            float ImgRatio = imgWidth / (float)imgHeight;  //影像寬高比
  13.            //獲取顯示控制元件大小
  14.            int BoxWidth = showRect.Width;  
  15.            int BoxHeight = showRect.Height;  
  16.            float BoxRatio = imgWidth / (float)imgHeight;  //顯示控制元件寬高比
  17.            //計算實際顯示區域大小,防止影像畸變顯示
  18.            int BufferWidth, BufferHeight;     
  19.            if (BoxRatio >= ImgRatio)  
  20.            {  
  21.                BufferHeight = BoxHeight;  
  22.                BufferWidth = (int)(BoxHeight * ImgRatio);  
  23.            }  
  24.            else
  25.            {  
  26.                BufferWidth = BoxWidth;  
  27.                BufferHeight = (int)(BoxWidth/ImgRatio);  
  28.            }  
  29.            //構建點陣圖
  30.            Bitmap bitmap = new Bitmap(BufferWidth, BufferHeight,  
  31.                                     System.Drawing.Imaging.PixelFormat.Format24bppRgb);  
  32.            if (bandlist.Length==3)     //RGB顯示
  33.            {  
  34.                int[] r = newint[BufferWidth * BufferHeight];  
  35.                Band band1 = ds.GetRasterBand(bandlist[0]);  
  36.                band1.ReadRaster(0, 0, imgWidth, imgHeight, r, BufferWidth ,BufferHeight, 0, 0);  //讀取影象到記憶體
  37.                //為了顯示好看,進行最大最小值拉伸顯示
  38.                double[] maxandmin1 = { 0, 0 };  
  39.                band1.ComputeRasterMinMax(maxandmin1,0);  
  40.                int[] g = newint[BufferWidth * BufferHeight];  
  41.                Band band2 = ds.GetRasterBand(bandlist[1]);  
  42.                band2.ReadRaster(0, 0, imgWidth, imgHeight, g, BufferWidth, BufferHeight, 0, 0);  
  43.                double[] maxandmin2 = { 0, 0 };  
  44.                band2.ComputeRasterMinMax(maxandmin2, 0);  
  45.                int[] b = newint[BufferWidth * BufferHeight];  
  46.                Band band3 = ds.GetRasterBand(bandlist[2]);  
  47.                band3.ReadRaster(0, 0, imgWidth, imgHeight, b, BufferWidth, BufferHeight, 0, 0);  
  48.                double[] maxandmin3 = { 0, 0 };  
  49.                band3.ComputeRasterMinMax(maxandmin3, 0);  
  50.                int i, j;  
  51.                for (i = 0; i < BufferWidth; i++)  
  52.                {  
  53.                    for (j = 0; j < BufferHeight; j++)  
  54.                    {  
  55.                        int rVal=Convert.ToInt32(r[i + j * BufferWidth]);  
  56.                        rVal = (int)((rVal - maxandmin1[0]) / (maxandmin1[1] - maxandmin1[0]) * 255);  
  57.                        int gVal=Convert.ToInt32(g[i + j * BufferWidth]);  
  58.                        gVal = (int)((gVal - maxandmin2[0]) / (maxandmin2[1] - maxandmin2[0]) * 255);  
  59.                        int bVal=Convert.ToInt32(b[i + j * BufferWidth]);  
  60.                        bVal = (int)((bVal - maxandmin3[0]) / (maxandmin3[1] - maxandmin3[0]) * 255);  
  61.                        Color newColor = Color.FromArgb(rVal, gVal, bVal);  
  62.                        bitmap.SetPixel(i, j, newColor);  
  63.                    }  
  64.                }  
  65.            }   
  66.            else//灰度顯示
  67.            {  
  68.                int[] r = newint[BufferWidth * BufferHeight];  
  69.                Band band1 = ds.GetRasterBand(bandlist[0]);  
  70.                band1.ReadRaster(0, 0, imgWidth, imgHeight, r, BufferWidth, BufferHeight, 0, 0);  
  71.                double[] maxandmin1 = { 0, 0 };  
  72.                band1.ComputeRasterMinMax(maxandmin1, 0);  
  73.                int i, j;  
  74.                for (i = 0; i < BufferWidth; i++)  
  75.                {  
  76.                    for (j = 0; j < BufferHeight; j++)  
  77.                    {  
  78.                        int rVal = Convert.ToInt32(r[i + j * BufferWidth]);  
  79.                        rVal = (int)((rVal - maxandmin1[0]) / (maxandmin1[1] - maxandmin1[0]) * 255);  
  80.                        Color newColor = Color.FromArgb(rVal, rVal, rVal);  
  81.                        bitmap.SetPixel(i, j, newColor);  
  82.                    }  
  83.                }  
  84.            }  
  85.            return bitmap;  
  86.        }  

3、  主函式呼叫

  得到Bitmap,我們就可以在程式中呼叫它了。我們可以在窗體上加一個PictureBox控制元件來顯示影象,其name設為pictureBox1。主要呼叫程式碼如下:

  1. privatevoid 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.             if (filename == "")  
  11.             {  
  12.                 MessageBox.Show("影像路徑不能為空");  
  13.                 return;  
  14.             }  
  15.         OSGeo.GDAL.Dataset ds= Gdal.Open(filename, Access.GA_ReadOnly);  
  16.         if(ds==null)  
  17.         {  
  18.         MessageBox.Show("影像開啟失敗");  
  19.         return;  
  20.         }  
  21.         Rectangle pictureRect = new Rectangle();  
  22.             pictureRect.X = 0;  
  23.             pictureRect.Y = 0;  
  24.             pictureRect.Width = this.pictureBox1.Width;  
  25.             pictureRect.Height = this.pictureBox1.Height;  
  26.         int[] disband = {3,2,1};  
  27.         Bitmap bitmap = GetImage(ds, pictureRect, disband);   //遙感影像構建點陣圖
  28.             pictureBox1.Image = bitmap;                   //將點陣圖傳遞給PictureBox控制元件進行顯示
  29.     }  




4、  結果展示

    這樣我們就可以很容易地顯示遙感影像了。



相關推薦

基於GDAL遙感影像顯示C#

        說明:本文章轉載自:http://blog.csdn.net/rsyaoxin/article/details/9220735         接觸GDAL有四五年多時間了,平時都是在C++下使用,最近需要在C#下呼叫GDAL,所以就開始學習了下,相

資料結構實現 4.1:集合_基於二分搜尋樹實現C++

資料結構實現 4.1:集合_基於二分搜尋樹實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 5.1:對映_基於樹實現C++

資料結構實現 5.1:對映_基於樹實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3. 演算法複

資料結構實現 10.2:對映_基於AVL樹實現C++

資料結構實現 10.2:對映_基於AVL樹實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3.

資料結構實現 6.4:優先佇列_基於連結串列實現C++

資料結構實現 6.4:優先佇列_基於連結串列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 6.3:優先佇列_基於動態陣列實現C++

資料結構實現 6.3:優先佇列_基於動態陣列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 6.2:優先佇列_基於最大二叉堆實現C++

資料結構實現 6.2:優先佇列_基於最大二叉堆實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 6.1:二叉堆_基於動態陣列實現C++

資料結構實現 6.1:二叉堆_基於動態陣列實現(C++版) 1. 概念及基本框架 1.1 滿二叉樹 1.2 完全二叉樹 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作

資料結構實現 5.2:對映_基於連結串列實現C++

資料結構實現 5.2:對映_基於連結串列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3. 演

資料結構實現 4.2:集合_基於連結串列實現C++

資料結構實現 4.2:集合_基於連結串列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

基於opencv 識別、定位二維碼 c++

前言 因工作需要,需要定點陣圖片中的二維碼;我遂查閱了相關資料,也學習了opencv開源庫。通過一番努力,終於很好的實現了二維碼定位。本文將講解如何使用opencv定位二維碼。 定位二維碼不僅僅是為了識別二維碼;還可以通過二維碼對影象進行水平糾正以及相鄰區域定位。定位二維碼,不僅需要影象處理相關知識,還需要

自動發牌C#

using ide bsp eric read over void log 成員 利用數組實現發牌過程 一副牌去掉大小王,還剩52張。一共東、南、西、北四家,每家隨機發13張牌。 提示: 東、南、西、北四家用一維數組表示 每家的牌采用一維數組表示(13張)

循環鏈表的創建、插入、刪除、逆序、顯示C++實現

i++ pos str pre hide mar add 這樣的 itl 對於單鏈表,因為每一個結點僅僅存儲了向後的指針。到了尾標誌就停止了向後鏈的操作,這樣,其中某一結點就無法找到它的前驅結點了。 對於單鏈表的操作大家能夠看我的這篇博客http://

WGS-84經緯度轉Web墨卡托投影C#

clas double light param urn static 實測 坐標 [1] /// <summary> /// WGS84經緯度轉Web墨卡托投影 /// </summary>

如何打造網站克隆、仿站工具C#

精神 復制 too empty 新建 webkit [] 處理 run 前兩天朋友叫我模仿一個網站,剛剛開始,我一個頁面一個頁面查看源碼並復制和保存,花了我很多時間,一個字“累”,為了減輕工作量,我寫了個網站“克隆工具”,一鍵克隆,比起人工操作, 效率提高了200%以上,精

簡單約瑟夫環模板C++

hdu2211 #include <bits/stdc++.h> using namespace std; int t; long long n,k; //函式返回的就是勝利者編號 long long cir(long long n,long long m){ /

樹形dp模板C++

poj2342 最簡單的樹形dp入門,樹上的最大點權獨立集 #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=6e3

Prim模板C++

hiho1097 Prim和Dijkstra很像,這裡也是用鄰接矩陣存的,應該也能改成堆優化的吧,然後就是鬆弛條件那裡和dijk不一樣 #include <bits/stdc++.h> using namespace std; const int N=1e3+50; co

Kruskal模板C++

hiho1098 並查集 對邊權排序 貪心取邊權小的邊 #include <bits/stdc++.h> using namespace std; const int N=1e5+50; const int M=1e6+50; int n,m,u,v,w; int p[N

資料結構實現:連結串列棧C++

資料結構實現(六):連結串列棧(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入棧操作 2.2 出棧操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析 3.1