ENVI+IDL使用

在面對大批量遙感影像數據重複操作的時候,我們會想到批處理的方式。儘管遙感軟件提供了一些批處理的方式,就小部分需求而言,單一的批處理方式往往是不夠的,這時候程序化處理就派上用場了。

(當然,也可以使用建模的方式做這個事情)

使用程序化處理的好處在於可以將一個複雜的地理處理工作流一次執行完成,靈活,可以按照自己需求來定,而無需中間過多的數據拷貝、轉換處理過程。可是另一個問題也接踵而至,當我們藉助於程序的時候,ENVI+IDL那些惱人、龐雜的程序知識也迫使大部分人放棄這一手段。如果使用ENVI+IDL的話,需要學習IDL語言、ENVI軟件,萬一使用的人跑偏了呢,那就不得不在IDL編輯器、面向過程和麪向對象程序設計、界面編程、可視化編程與ArcGIS集成的沼澤裏苦苦掙扎了。

(其實我們的目的很簡單,只要把這批數據處理好了就行啊)

對於一個批處理地理任務問題而言,無外乎就是數據的輸入、數據處理和數據導出三個小任務(這一思路適用於所有的數據程序化處理過程),至於那些界面、可視化的編碼實在是根本用不到有木有。多年前,IDL使用的是過程編碼,後續面向對象興起,馬上轉投面向對象編碼,然後又突然告訴使用的這幫人,面向對象比面向過程方便,也是讓使用ENVI+IDL的人又心累了一把。

(帶別人跳坑,然後又把人從坑裏撈出來,你不嫌累啊)

本文使用面向對象的程序設計,大致講述ENVI+IDL編碼過程,儘量省去那些界面編程、可視化編程的繁瑣細節,內容有:IDL工作臺、數據輸入、數據處理、數據導出四個方面。至於IDL編碼規範也會部分涉及,但此項不是重點。

1、IDL編輯器使用

在安裝ENVI的時候會自動安裝IDL編程軟件。在軟件安裝完畢後,在開始菜單上會新增ENVI和IDL的應用程序,點擊IDL8.5(ENVI版本不一樣,IDL版本也會不一樣),就可以看到IDL的工作臺了,工作臺主要有資源管理器、過程編輯界面和控制檯三個。可以在菜單欄的新建文件按鈕上,點擊新建文件,寫入如下語句:

pro hellow
e=envi()

;核心語句,獲取一個ENVI對象,加載到內存中。
end

(注:IDL過程語句語法結構爲:pro xxx    end )

點擊右上角的編譯、運行,一個ENVI對象就啓動運行了。

在程序執行完畢的時候,是需要回收ENVI內存資源的,應加上ENVI對象關閉語句:e.Close 

pro hellow
e=envi()
e.Close
end

e=envi()和e.Close之間就是編寫具體的代碼了。

2、數據的輸入(數據訪問)

(1)單個數據輸入

面向對象ENVI+IDL本身也是有數據訪問函數的,查看ENVI程序設計幫助,如下:

單個數據導入語法爲:Result ENVI.OpenRaster(URI [, Keywords=value]),該語句返回一個ENVI柵格數據對象。

注:ENVI函數的形參有必選參數和非必選參數,必選參數和非必選參數用逗號隔開,位於中括號外面的爲必選參數(教程一般說是位置參數),中括號裏面的爲非必選參數(教程說是關鍵詞),部分非必選參數是不能同時存在的,只能選一個。

        URL:位置參數,對於本地數據而言,URL是遙感影像數據在本地磁盤的詳細路徑,對於遠程數據而言,URL是一個遠程訪問地址,如果帶有訪問權限的遠程數據,還需要輸入用戶名和密碼。

         Keywords :關鍵詞,指在創建這個柵格數據對象時的一些初始化設置。如數據類型、需要忽略的值,數據集名字、擴展類型、元數據、遠程數據用戶和密碼等等。

假如數據路徑爲:D:\Program Files\Exelis\ENVI53\data\qb_boulder_msi.hdr

那麼該數據的導入爲:

e = ENVI()  

;如果在參數里加/headless 關鍵字,爲不顯示ENVI軟件

file='D:\Program Files\Exelis\ENVI53\data\qb_boulder_msi.hdr'

raster=e.OpenRaster(file)                                     

如果是使用單個數據集,寫好這一步就算完成數據的導入了。                    

                                             (可以再加兩條代碼測試,如:view1 = e.GetView()

                                                                                             ;獲取視圖對象

                                                                                            layer1 = view1.CreateLayer(raster) 

                                                                                            ;在視圖中顯示柵格數據     )

(注:與C/C++、JAVA、python不同的是,反斜杆並不是轉義符,IDL路徑分割符斜杆與反斜槓都是一樣的,也可以寫成這樣:file='D:/Program Files/Exelis/ENVI53/data/qb_boulder_msi.hdr',但是IDL函數關鍵詞引用爲斜杆,IDL不區分字母大小寫)

(2)批量數據導入

面向對象ENVI+IDL並不支持批量數據的導入,如果需要批量導入數據,需要使用IDL文件操作函數配合ENVI::OpenRaster一起使用。其意義在於遍歷文件夾下所有數據,並且使用通配符進行查詢篩選,將所需要的數據路徑保存至一個字符串數組裏,然後再使用循環語句遍歷該字符串數組,通過ENVI::OpenRaster依次打開。

(IDL文件操作函數:

                                          

比較常用的文件函數有:FILE_COPY(拷貝文件),FILE_SEARCH (文件搜索)、FILEPATH(文件完全路徑)。)

批量導入數據使用的核心文件操作函數是FILE_SEARCH (文件搜索)。

語法爲:Result = FILE_SEARCH(Path_Specification),該函數返回一個字符串數組,參數Path_Specification文件夾路徑,並且可以使用通配符,使得字符串數組包含所有Path_Specification文件夾匹配的文件路徑。IDL通配符與shell通配符一致,有:* ?{}等。

比如D:\Program Files\Exelis\ENVI53\data文件夾下:

搜索所有帶後綴名爲.hdr的文件:

filesearch='D:\Program Files\Exelis\ENVI53\data'

files=FILE_SEARCH(filesearch,'*.hdr')

查詢files字符串結果如下:

(補充通配符搜索:

如果是搜索所有hdr文件中含有set的文件:

files=FILE_SEARCH(filesearch,'*set*.hdr')

如果是搜索所有包含.hdr和.enp後綴的文件:

files=FILE_SEARCH(filesearch,'*.{hdr,enp}')

以上也可以使用界面DIALOG_PICKFILE函數來實現多個文件的選擇,按住ctrl鍵手動選擇多個文件,返回一個字符串數組。

files = DIALOG_PICKFILE(/MULTIPLE_FILES)

由於是先在遍歷該文件夾下文件路徑的時候,未獲取文件數目多少,可以使用數組處理函數來獲取整個的文件數目。

1)size()函數,返回數據信息的一個整型數組,整型數組第二個數字存儲了該整型數組的大小:

stringsize=size(files)

count1=stringsize(1)

或者使用/N_elements關鍵字參數獲取字符串數組大小

count2=size(files,/N_elements)

2)N_elements()函數,返回數組大小

count3=N_elements(files)

3)在使用FILE_SEARCH()函數時,直接將關鍵字遍歷文件數目count=xx,傳出。

files=FILE_SEARCH(filesearch,'*.hdr',count = count4)

3、數據處理

(1)循環語句

獲取到符合條件的影像路徑後就可以使用循環語句進行影像數據的遍歷與任務執行了。

循環語句語法:

1)for語句 for i=m,n(,step) do begin 語句 endfor ;

當i從m以步長inc(若不設置,默認爲1)逐步變化到n時,循環執行語句。

2)while語句 while 條件 do begin 語句 endwhile ;

當條件表達式的值爲真時,while語句循環體執行語句序列,先判斷循環條件,如果條件滿足,再執行循環體,否則跳出。

3)repeat語句 repeat begin 語句 endrep until 條件

先執行循環體,然後在判斷條件表達式。哪怕是條件表達式爲假,循環體也要執行一次。

 

在這裏使用第一種循環語句,加入參數m,是爲了查看是否循環執行完畢。

pro hello
  e=envi(/headless)
  filesearch='D:\Program Files\Exelis\ENVI53\data'
  files=FILE_SEARCH(filesearch,'*.hdr',count=countall)
  m=0
  for i=0,countall-1 do begin
     tmp=e.OpenRaster(files[i])
     m = m+1
  endfor
  print,m

end

m參數最後結果是16,說明執行完畢。

(2)任務處理(TASK)

ENVI的任務處理包含了衆多的TASK,如:影像平滑、增強、幾何糾正、光譜糾正、波段運算、變化檢測、融合、配準、拼接、掩模、裁剪,分類、分類後處理(矢量柵格轉化、矢量小面積處理)、格式轉換等等,ENVI5.3有將近150個TASK模塊。

由於各模塊需要的參數不一致,TASK的參數裝配千差萬別,爲說明TASK執行任務過程,以下以一個柵格數據爲例說明TASK裝配過程:

1)引用TASK任務,如:百分比線性拉伸

Task=ENVITask('LinearPercentStretchRaster')

2)裝配TASK任務參數,TASK任務參數既包括輸入、輸出參數,也包含該任務的特殊參數,比如百分比線性拉伸按照多少百分比的像素值分佈對原始圖像進行拉伸。

pro hello
  compile_opt idl2
  e=envi()

 

 ;導入柵格數據
  file='D:\Program Files\Exelis\ENVI53\data\qb_boulder_msi.hdr'
  raster=e.OpenRaster(file)

 

;引入LinearPercentStretchRaster TASK任務
  Task=envitask('LinearPercentStretchRaster')
 

;設置TASK參數
  Task.INPUT_RASTER=raster
  Task.PERCENT = 10.0
  Task.OUTPUT_RASTER_URI='f:\file\qb_boulder_LinearPercentStretch'

 

;執行TASK任務
  Task.Execute
end

3)執行TASK

  Task.Execute

10%線性拉伸效果如下:

(3)數據導出

在執行TASK任務之前,只要設置好Task.OUTPUT_RASTER_URI的輸出路徑,即可將數據輸出。由於執行的是批量處理任務,因此,在輸出路徑時,還需要自動的獲取輸出路徑。由於路徑是一個個的字符串,可以使用字符串處理函數來截取數據。假定其中一個原始柵格數據的路徑爲:file='D:\Program Files\Exelis\ENVI53\data\qb_boulder_msi.hdr',截取文件名方法如下:

1)直接使用文件操作函數FILE_BASENAME()截取,返回文件名

str=FILE_BASENAME(file,'.hdr')

2)我們需要截取該柵格數據的文件名qb_boulder_msi,由於qb_boulder_msi位於反斜槓和點號之間,因此可以通過這三者之間的關係得到。

獲取最右邊斜槓的位置:

pos=strpos(file,'\',/reverse_search)

截取反斜槓右邊的字符串:

str1=strmid(file,pos+1)

獲取點號的位置:

pos=strpos(str1,'.',/reverse_search)

截取文件名:

str=strmid(str1,0,pos)

上面兩種方法用到了文件操作函數或者字符串處理函數,這是在IDL處理路徑字符串中最常用的方法。

假如指定批量輸出的文件夾路徑爲:files1='F:\file' 那麼輸出的完整路徑應爲:

file=files1+'\'+str

最後再裝配到TASK處理路徑中

Task.OUTPUT_RASTER_URI=files2

因此,配合循環,整個執行過程爲:

pro hello
  compile_opt idl2
  e=envi(/headless)
  filesearch='D:\Program Files\Exelis\ENVI53\data'
  files=FILE_SEARCH(filesearch,'*.hdr',count=countall)
  files1='F:\file'
  for i=0,countall-1 do begin
    str=FILE_BASENAME(files[i],'.hdr')
    file=files1+'\'+str
    raster=e.OpenRaster(files[i])
    Task=envitask('LinearPercentStretchRaster')
    Task.INPUT_RASTER=raster
    Task.PERCENT = 10.0
    Task.OUTPUT_RASTER_URI=file
    Task.Execute
  endfor
  e.close
 end

處理結果如下:

上述過程中都是一些代碼的搬運過程,整個任務流程也不需要什麼深層干預,因爲ENVI+IDL已經將相關函數封裝好了。如果真正涉及到內部算法,沒有深厚的數據結構功底,純粹做底層算法研發,也實在是癡人說夢。從某個角度說,這或許是如今python如此流行的原因,基本上在網上弄一些函數庫,然後幾行代碼就搞定了,至於說研究,不是搞笑嘛,各種COPY,各種搬運。。。

波段運算對應數組處理

文件路徑對應字符串處理

控制語句對應批處理

以上三個需要與ENVI的函數靈活搭配。

 

 

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