基於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。關於編譯的方法網上很多教程,我就不介紹了,具體編譯步驟可以參照民錄大哥的部落格:
如果很難編譯成功,需要編譯後的版本,可以留下郵箱,或者給我發郵件[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一起。
我們首先建立一個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 = newint[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 = newint[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 = newint[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 = newint[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。主要呼叫程式碼如下:
- privatevoid 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、 結果展示
這樣我們就可以很容易地顯示遙感影像了。
相關推薦
基於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