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

來源:互聯網
上載者:User

        接觸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、  結果展示

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

    

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.