深入解析GDAL庫的RasterIO()函數

轉自:http://blog.csdn.net/liminlu0314/article/details/8301585

首先說明一下GDALRasterBand的RasterIO函數,波段類的RasterIO函數相比GDALDataset類的RasterIO函數比較簡單,先從這個簡單的說起。圖像還是以上面的圖爲例,我們只取第一個波段爲例進行說明。第一個波段的圖像如下圖所示:

                                                    

                                                                                 圖1:第一張波段示意

我們再把GDALRasterBand的RasterIO函數接口拿過來,形式如下:

CPLErr GDALRasterBand::RasterIO(GDALRWFlageRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void *pData,int nBufXSize,int nBufYSize,GDALDataTypeeBufType,int nPixelSpace,int nLineSpace)

第一個參數eRWFlag就是讀寫標記,用來指定你是讀取圖像還是寫入圖像,很簡單。

        接下來的四個參數是用來指定讀寫圖像的範圍的,其中前兩個用來說明讀取的位置,起始行列號,後兩個是讀寫圖像的寬度和高度,比如我們要在上面的圖1中讀取一個大小爲300×200的矩形區域,從位置(100,200)開始讀取,如圖2所示:圖中左上角紅色的座標(100,200)就是起始位置,分別對應於第二個參數nXOff和第三個參數nYOff,圖中的Width=300就對應於第四個參數nXSize,圖中的Height=200就對應於第五個參數nYSize。這樣就確定了我們要讀取或者寫入圖像的位置和大小了。                                                 

                                                         

                                                                                   圖2:RasterIO參數說明

第六個參數void* pData就是用來存儲圖像的元素值的地方,如果是讀取圖像,那麼讀取出來的圖像像素值就存儲在這個pData中,如果是寫入圖像,那麼這個pData中的數據會被寫入到圖像上指定的位置中去。那麼這個pData的數組大小是多少呢?別急,這個pData的大小是有後面兩個參數確定的,即nBufXSize和nBufYSize,這個pData的大小一定不能小於nBufXSize×nBufYSize,否則RasterIO的返回值是錯誤的(很多人可能都覺得RasterIO沒有返回值,RasterIO是有返回值的,是一個int類型的枚舉值,如果這個函數返回的不是CE_None,就是0,那麼RasterIO就出錯了,出錯的意思就是讀取的時候可能沒讀出數據,寫入的時候沒有寫到圖像中去)。這兩個參數的意義不僅僅這麼簡單,他們還有更牛逼的功能,就是用來縮放圖像。比如圖2中,讀取圖像的範圍是300×200,如果我要讀取圖像中的原始數據,那麼這兩個參數分別應該設置爲nBufXSize=300和nBufYSize = 200。這樣的用法是最常用的也是最簡單的。如果我把這兩個參數的值設置爲nBufXSize=150和nBufYSize=100會發生什麼情況呢?恭喜你,你會得到圖3中矩形框的一個縮小的圖像,也就是行和列都縮小一半,等等,什麼意思,我好想沒搞明白。縮小一半的意思就是自動把圖2中的矩形區域中的灰度值重採樣,重採樣結果的大小就是你設定的這個150×100。那再比如說,把這兩個參數的值設置爲nBufXSize=600和nBufYSize=400,讀出來的數據就是把圖2中的矩形區域圖像重採樣至原來的兩倍。當然了,這個都是GDAL內部自動實現的,重採樣方式默認使用的是最鄰近採樣。如果設置的nBufXSize和nBufYSize與nXSize和nYSize不一樣的話,同時圖像沒有金字塔的話,速度可能會慢,如果有金字塔的話,速度就會很快了。

圖3是圖2中矩形區域的圖像,圖4是設置nBufXSize=150和nBufYSize=100讀取出來的圖像,圖5是設置nBufXSize=600和nBufYSize=400讀出來的圖像。

                                                                      

                                                                           圖3 nBufXSize=300和nBufYSize=200讀取圖像

                                                                                      

                                                                           圖4 nBufXSize=150和nBufYSize=100讀取圖像

                                   

                                                                                       圖5 nBufXSize=600和nBufYSize=400讀取圖像

        接下來是第九個參數nBufType,意思是將數據讀取的數據類型,這個參數和pData有密切的關係(不過從pData開始,後面的參數都是和pData相關的),nBufType就是用來標記pData的類型,比如pData是char,那麼nBufType就是GDT_Byte,如果pData是float類型,那麼就是GDT_Float32,如果pData是double類型,那麼就是GDT_Float64等等。這個參數和圖像的數據類型沒有多大關係,只要和pData的類型一致就不會出錯。如果這個參數和圖像的數據類型設置的不一致,不會報錯,但是讀出來的數據可能是錯的,當然,這個是有規律的,具體的規律就是,如果圖像的GDT_Byte類型的,那麼這個參數設置任何類型都能把圖像中的數據讀出來。如果圖像數據類型是GDT_Float32,這個參數設置爲GDT_Byte,那麼讀出來的數據就是錯的。那麼這是爲什麼呢?主要的原因就是C/C++的數據類型轉換的時候精度丟失的問題,開始圖像是GDT_Byte類型,也就是圖像裏面的值都是用無符號的char來存的,那麼後面不管你的pData類似是char,short,int,float還是double,都可以把無符號的char存進去;但是如果圖像是float類型,你後面pData是個無符號char類型,那麼在把一個float的數賦值給一個char肯定會丟失啊,假如這個float數是300.0,char是不可能存超過0~255,或者-127~128之外的數據的,這樣就會造成數據截斷。關於這部分可以參考《深入理解計算機系統》這本書。此外,關於這部分可以參考之前的那篇RasterIO博客。


      到這裏就剩下最後兩個參數了,nPixelSpace和nLineSpace,這兩個參數是用來控制參數pData中像元的存儲順序的,nPixelSpace表示的是當前像素值和下一個像素值之間的間隔,nLineSpace表示當前行和下一行的間隔,單位都是按照字節爲單位計算。這兩個值默認給0,表示的是,nPixelSpace=sizeof(DataType),nLineSpace=nBufXSize*sizeof(DataType),什麼意思呢,意思就是,當前像素和下一個像素是緊接的;當前行和下一行的距離是一行像素。可能這個說法還是有些抽象,簡單的說,就是默認讀取出來的圖像的像素值在pData這個數組中的順序是按照從左到右,從上到下的順序存儲的。通過這兩個參數,可以很容易的對pData中的數據進行排序,比如默認是是從左到右,從上到下的順序存儲,那麼假如我要讀取按照從上到下,從左到右的順序存儲的話,該怎麼設置?OK,從上到下,從左到右,也就是第一個像素的下一個像素是在下一行,所以nPixelSpace應該等於一行像素的大小,即nBufXSize*sizeof(DataType),第一行和下一行的間隔就是最右邊的唄,所以nLineSpace的值就是sizeof(DataType)。


        至此,我們已經把GDALRasterBand類的RasterIO的函數做了一個詳細的說明。下面開始對GDALDataset類的RasterIO做一個說明。GDALDataset類的RasterIO和GDALRasterBand類的RasterIO的接口基本一樣,除了多了幾個參數。除了多出來的參數我會在下面說明,沒有多出來的意義和上面的一樣,下面不再贅述。還是一樣,我們先把GDALDataset類的RasterIO接口列出來,形式如下:

CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,intnBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,int nPixelSpace,intnLineSpace,int nBandSpace)

     OK,我們從第一個參數開始,遇到和上面一樣的,請直接回去看上面的說明。從第一個一直到第九個,和上面的一樣,跳過。第十個參數nBandCount,這個參數用來指定讀取的波段的個數,首先我們要有個背景知識,就是GDALDataset裏面有很多個GDALRasterBand,比如一個普通的照片,至少有三個波段,即RGB。所以這個參數就是用來說明我要讀取的波段的個數,比如TM的數據有7個波段,我只要讀取其中的三個來進行顯示,那麼就把這個參數設置爲3即可。到這裏可能有人問了,我從7個波段選擇3個波段,假如這七個波段的編號是1、2、3、4、5、6、7,那麼我選擇3個,怎麼選擇呢?很好,至於怎麼指定選擇的3個波段,就是下一個參數panBandMap要做的事情了。這個參數是一個int指針,也就是一個int的數組。還是上面的例子,TM的數據7個波段,4、3、2波段組合是假彩色圖像,假如我們現在要讀取這個4、3、2分別用來顯示,那麼只要把這個int panBandMap[3] = {4,3,2},把這個值設置進去就好了。如圖6所示:

                                                                

         接下來是nPixelSpace和nLineSpace以及nBandSpace這三個參數,前兩個上面已經說明過了,這個nBandSpace是個神馬東西啊?根據字面的意思就是當前波段和下一個波段之間的間隔,單位還是以字節爲單位。這三個參數和上面一樣,默認都可以設置爲0,這樣的結果就是,pData中存儲圖像像元的順序是先是第一個波段,再是第二個波段,以此類推,每個波段裏面按照從左到右,從上到下的順序存儲。假如是一個RGB的圖像,那麼讀出來的順序就是 RRRR…(一共有Width×Height個R)GGG…(一共有Width×Height個G)BBB…(一共有Width×Height個B)。這個默認的方式有時候可能就不太方便,比如用來構造BMP圖像用來顯示的時候,BMP中圖像存儲順序是按照RGBRGBRGB…(一共有Width×Height個RGB對)排列的。要實現這種排列方式,就可以設置上面三個參數來達到這個目的。我們先來分析一下,RGB的話,第一個像素和第二個像素之間的間隔隔了兩個像素,RGBR,中間有GB兩個值,所以nPixelSpace的值就是sizeof(DataType)*3;第一行和下一行的間隔就是隔了原來的兩行數據,所以nLineSpace的值就是sizeof(DataType)*3×width;第一個波段和下一個波段之間的距離就是一個像素,RGB,R是第一個波段G是第二個波段,中間間隔可不就是1個像素值麼,所以nBandSpace的值就是sizeof(DataType)。                                                                             



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章