程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 使用C#版本GDAL讀取復數圖像

使用C#版本GDAL讀取復數圖像

編輯:C#入門知識

GDAL的C#版本雖然在很多算法接口沒有導出,但是在讀寫數據中的接口基本上都是完全導出了。使用ReadRaster和WriteRaster方法來進行讀寫,同時對這兩個方法進行了重載,對於常用的數據類型可以不用指定數據類型直接進行讀取即可。但是對於復數類型就有點復雜了。下面就針對GDAL如何來讀取復數數據來進行一個簡單的說明。

我們知道,在使用GDAL讀取數據的時候使用的是ReadRaster這個函數,這個函數重載了6個,函數聲明分別如下,以Dataset的ReadRaster為例,Band類中的ReadRaster與之類似。

OSGeo.GDAL.Dataset.ReadRaster(System.Int32, System.Int32, System.Int32, System.Int32, System.Byte[], System.Int32, System.Int32, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32);
OSGeo.GDAL.Dataset.ReadRaster(System.Int32, System.Int32, System.Int32, System.Int32, System.Int16[], System.Int32, System.Int32, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32);
OSGeo.GDAL.Dataset.ReadRaster(System.Int32, System.Int32, System.Int32, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32);
OSGeo.GDAL.Dataset.ReadRaster(System.Int32, System.Int32, System.Int32, System.Int32, System.Single[], System.Int32, System.Int32, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32);
OSGeo.GDAL.Dataset.ReadRaster(System.Int32, System.Int32, System.Int32, System.Int32, System.Double[], System.Int32, System.Int32, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32);
OSGeo.GDAL.Dataset.ReadRaster(System.Int32, System.Int32, System.Int32, System.Int32, System.IntPtr, System.Int32, System.Int32, OSGeo.GDAL.DataType, System.Int32, System.Int32[], System.Int32, System.Int32, System.Int32);
前五個函數的聲明基本上完全一致,除了第五個參數,分別是Byte[],Int16[],Int32[],Single[],Double[]。分別對應的是將圖像中的像素值使用8U,16U\16S,32U\32S,32F和64F。如果圖像數據是普通的數據(這裡指的是除復數圖像之外),那麼這五個函數完全可以滿足所有的需求。但是如果圖像是復數圖像(復數圖像就是圖像的像素值是由復數組成的,比如通過傅立葉變換後的圖像),這時,上面的五個函數就有點愛莫能助了,就需要上面的第六個函數來出場救急了。

第六個函數的聲明和C\C++的聲明完全一致,使用C\C++的同學對這個接口應該比較熟悉。這個函數可以替代上面五個函數來使用,但是比較麻煩的時,就是傳入的參數會比較多,首先看一個例子。使用普通的方式來讀取一個單波段8U的數據(Landsat5的一個數據)。從數據中讀取100×100大小的數據,直接使用ReadRaster的Byte接口。

static void ReadRaster()
{
	string strFile = @"D:\Data\landsat\etp139r26_5t19900902\p139r26_5t19900902_nn1.tif";

	OSGeo.GDAL.Gdal.AllRegister();
	OSGeo.GDAL.Dataset ds = OSGeo.GDAL.Gdal.Open(strFile, OSGeo.GDAL.Access.GA_ReadOnly);
   
	int []bandmap = new int [1];
	bandmap[0] = 1;

	//讀取Byte類型
	Byte[] data = new Byte[100 * 100];
	OSGeo.GDAL.CPLErr err = ds.ReadRaster(3000, 2000, 100, 100, data, 100, 100, 1, bandmap, 0, 0, 0);
	
	//將讀取的數據輸出
	for (int i = 0; i < 100; i++ )
	{
		for (int j = 0; j < 100; j++)
		{
			Console.WriteLine("{0}", ddata[i*100+j]);
		}
	}
	Console.WriteLine("done\n");
}
下面看看如何使用第六個接口來完成上面的功能,代碼如下:

static void ReadRaster()
{
	string strFile = @"D:\Data\landsat\etp139r26_5t19900902\p139r26_5t19900902_nn1.tif";

	OSGeo.GDAL.Gdal.AllRegister();
	OSGeo.GDAL.Dataset ds = OSGeo.GDAL.Gdal.Open(strFile, OSGeo.GDAL.Access.GA_ReadOnly);
   
	int []bandmap = new int [1];
	bandmap[0] = 1;

	//讀取Byte類型
	Byte[] data = new Byte[100 * 100];
	
	//構造一個IntPtr,大小為100×100個Byte
	IntPtr ptr = Marshal.AllocCoTaskMem(data.Length);
	//需要指明讀取的數據類型
	OSGeo.GDAL.CPLErr err = ds.ReadRaster(3000, 2000, 100, 100, ptr, 100, 100, OSGeo.GDAL.DataType.GDT_Byte, 1, bandmap, 0, 0, 0);
	//將讀取到的數據拷貝到data中
	Marshal.Copy(ptr, data, 0, data.Length);

	//將讀取的數據輸出
	for (int i = 0; i < 100; i++ )
	{
		for (int j = 0; j < 100; j++)
		{
			Console.WriteLine("{0}", ddata[i*100+j]);
		}
	}
	Console.WriteLine("done\n");
}
從上面的代碼中可以看出,使用第六個函數的時候,需要一個IntPtr的類型,使用Marshal類中的AllocCoTaskMem函數來進行分配內存空間(不知道C#中的說法是啥,按照C\C++中應該就是分配空間)。需要注意的是,分配的大小是按照字節(Byte)為單位的。接下來在調用ReadRaster時需要指定數據類型,調用之後,像素值應該都存儲在這個IntPtr中了,然後再使用Marshal類中的Copy函數將IntPtr中的數據拷貝到Byte數組data中即可。

通過上面的代碼,我們大致知道第六個ReadRaster的大致用法,接下來我們通過這個方法來讀取一個復數類型的圖像。沒有復數類型的圖像,可以使用ENVI隨便打開一個圖像,然後在Transform菜單下有個FFT,將打開的數據進行傅立葉變換,輸出的結果就是一個復數圖像。這裡我將上面使用的Landsat的數據使用FFT轉了下。使用下面的代碼進行打開。

static void ReadRaster()
{
	string strFile = @"D:\Data\landsat\etp139r26_5t19900902\p139r26_5t19900902_nn1_fft.tif";

	OSGeo.GDAL.Gdal.AllRegister();
	OSGeo.GDAL.Dataset ds = OSGeo.GDAL.Gdal.Open(strFile, OSGeo.GDAL.Access.GA_ReadOnly);
   
	int []bandmap = new int [1];
	bandmap[0] = 1;


	//讀取復數類型,由於一個復數由兩個數據組成,所以讀取100×100的像元需要2倍普通圖像的大小
	double[] data = new double[100 * 100 * 2];
	
	//構造一個IntPtr,大小為100×100×2個double,一個double為4個byte,所以下面的長度要乘以8
	IntPtr ptr = Marshal.AllocCoTaskMem(data.Length*8);
	//需要指明讀取的數據類型
	OSGeo.GDAL.CPLErr err = ds.ReadRaster(0, 0, 100, 100, ptr, 100, 100, OSGeo.GDAL.DataType.GDT_CFloat64, 1, bandmap, 0, 0, 0);
	//將讀取到的數據拷貝到data中
	Marshal.Copy(ptr, data, 0, data.Length*8);

	//將讀取的數據輸出
	int in1 = 0;
	for (int i = 0; i < 100; i++ )
	{
		for (int j = 0; j < 100; j++)
		{
			Console.WriteLine("({0}*i+{1})", ddata[in1++], ddata[in1++]);
		}
	}
	Console.WriteLine("done\n");
}
在上面的代碼中,一個復數由實部和虛部組成,所以一個像素值就對應於普通圖像的2個像素值,故讀取100×100大小的數據就需要分配普通圖像2倍的大小。除此之外與讀取普通圖像一樣,不過在最後獲取像素值的時候,復數圖像的像素值是順序存儲的,即實部,虛部,實部,虛部...這樣的順序來進行存儲。上面的代碼運行的前五個像素值如下圖所示:

\

通過ENVI軟件查看該圖像的前五個像素值如下圖所示(圖中紅色框中就是像素值),對比出來可以看到讀取出來的實部和虛部完全一樣。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD48cD48aW1nIHNyYz0="http://www.2cto.com/uploadfile/Collfiles/20140219/20140219093641418.jpg" alt="" />

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved