ENVI IDL读写数据
最近寫程序不知道怎么寫envi標準格式文件的頭文件,在網上搜了半天,也沒找到相關的信息。找到一個 ENVI_SETUP_HEAD函數,也不知怎么用。下面的內容可能以后用的著,先留著吧。
?? 引用自:http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=56472&page=1
在IDL中讀寫數據
??? 介紹IDL中的常用的輸入和輸出程序。IDL中的基本原則是:“只要有數據,就可以將其讀進IDL”。IDL對格式沒有要求,也不要求對數據進行準備。這使得IDL成為目前功能最強、最靈活的科學可視化分析語言。
具體來說,包含以下內容
1. 如何打開文件進行讀寫
2. 如何查找文件
3. 如何獲得文件I/O的邏輯設備號
4. 如何獲得機器的獨立文件名
5. 如何讀寫ASCII或格式化的數據
6. 如何讀寫二進制的或二進制數據
7. 如何處理大型數據文件
8. 如何讀寫通用的文件格式,如GIF和JEPG文件
?
1.打開文件進行讀寫
??? IDL中的所有輸入和輸出都是通過邏輯設備號完成的??梢园岩粋€邏輯設備設想為一個管道,這個管道連接著IDL和要讀寫的數據文件。要從一個文件中讀寫數據,必須首先把一個邏輯設備號連接到一個特定的文件。這就是IDL中三個Open命令的作用:
?? ?openr 打開文件進行讀。
??? openw 打開文件進行寫。
??? openu 打開文件進行更新(也就是說,讀和/或寫)。
??? 這三個命令的語法結構是完全相同的。首先是命令名,后面是一個邏輯設備號和要與該邏輯設備號相連的文件名。例如,將文件名temp596.dat和邏輯設備號20相連以便可以在此文件里寫入內容。如下:
??? OpenW, 20,’temp596.dat’
??? 將會看到Open命令更常用的書寫方式。例如:
??? OpenR, lun, filename
??? 此例中,變量lun保存了一個有效的邏輯設備號,變量filename代表一個機器特定的文件名,這個文件名將和此邏輯設備號聯系起來。
??? 注意,變量filename是一種機器特定的格式。這意味著如果它含有特定的目錄信息,它必須用本地機器的語法來表達。而且它在某些機器(比如,UNIX機器)上具有大小寫敏感性,因為在這些機器上文件名有大小寫敏感性。
查找和選擇數據文件
????IDL被廣泛使用的原因之一,是IDL可以在許多不同的計算機操作系統中運行。但由于不同的操作系統有不同的文件命名習慣(而且,特別用確定子目錄的不同方式),這在以獨立于機器的方式指定文件名方面提出了挑戰。幸好,IDL提供了一些工具可讓這項工作變得容易些。
1.1選擇文件名
??? 也許獲得機器獨立文件名最容易的方法是用Pickfile對話框。IDL命令允許用機器上自身的選擇文件的圖形對話框來交互式地從文件名列表中選擇一個文件名。例如,從本地目錄.pro文件列表中選擇一個文件名,可以鍵入如下命令:
??? IDL>filename=Dialog_Pickfile(Filter=’*.pro’,/Read)
??? 注意,這個命令在IDL5.0以前的版本中命名為Pickfile。
??? IDL5.2版通過關鍵字Multiple,賦予Dialog_Pickfile選擇多個文件名(若它們存在于同一個目錄下)的能力。使用了正常的依賴于平臺的選擇文件方式。例如,在用WinDOws操作系統的計算機上,通常先選擇第一個文件,接著用Shift鍵和鼠標點擊來選擇在第一個文件和第二個文件之間的所有文件,或者用Control鍵和鼠標點擊來選擇一個額外的文件。
??? IDL>filename=Dialog_Pickfile(Filter=’*.pro’,/Read,/Muitiple)
??? 如果要打開文件來寫而不是去讀,在對話框中,可用Write關鍵字代替Read關鍵字。甚至可以推薦一個缺省的文件名,鍵入:
??? IDL>outfile=Dialog_Pickfile(File=’default.dat’,/Write)
??? 從這個對話框中返回的是帶絕對路徑的文件名,其形式與運行IDL的機器有關。也就是說,它使用機器自身的文件命名語法。鍵入以下命令就可以看到:
??? IDL>Help, filename, outfile
??? 注意,Dialog_Pickfile對話框中有一個“取消”按鈕。若選擇“取消”按鈕,對話框會返回一個空字符串。所以在打開文件讀寫之前,總是希望檢查返回的名字是否為空。
IDL>IF outfile EQ ‘’ THEN Print, ’Whoops!’
1.2 選擇目錄名
??? 在IDL5.2中,Dialog_pickfile得到改進,因而它也能用于選擇目錄名而不僅是一個文件名。設置Directory關鍵字,在選擇窗口內只列出目錄而沒有文件。
?? IDL>directory=Dialog_Pickfile(/Directory)
?
2.尋找文件
?? ?另一個有用的命令是FindFile命令。此命令返回一個包含所有符合給定文件要求的文件名的字符串數組。這在IDL程序中用于自動匹配并打開文件的任務中非常有用,或者是在任何時候不知道一個目錄下有多少個文件的情況下,用于在該目錄下創建一批文件的任務中也是非常有用的。
?? ?例如,要打印出當前目錄下所有數據文件的長度(按字節計),可鍵入IDL代碼:
?? ?Files=findfile(‘*.dat’,count=numfiles)
??? If numfiles eq 0 then message,‘no data files here!’
??? FOR j=0,numfiles-1 DO BEGIN
?????? Openr, 10, files(j)
?????? fileinfo=fstat(10)
????? ?print,fileinfo.size
????? ?Close, 10
??? ENDFOR
??? 需要重點指出的是:FindFile命令中文件說明(’*.dat’)是以相對路徑名給出,而不是絕對路徑名。因此,命令返回也是相對路徑名,而不是絕對路徑名。這不同于Pickfile對話框,Pickfile總是返回絕對路徑名。
構造文件名
?? ?獲得機器獨立文件名的第三個很有用的IDL命令是Filepath命令。例如,假設要打開文件galaxy.dat,它在IDL主目錄下的 examples/data子目錄中??梢詾榇宋募嬙煲粋€機器獨立的絕對路徑名,鍵入:
??? IDL>galaxy=filepath(‘galaxy.dat’,Subdirectory=[‘examples’,’data’]
??? 如果想從其它的目錄開始而不是IDL主目錄,可以用Root_Dir關鍵字指定開始的目錄名。例如,要在當前目錄的子目錄coyote中構造此文件的一個路徑名,可以鍵入:
??? IDL>cd,current=thisdir
?? ?IDL>galaxy=filepath(‘galaxy.dat’,root_dir=thisdir,$
??? Subdirectory=’coyote’)
??? 注意:Filepath命令并沒有實際找到此文件,它只是構造了一個文件路徑名。構造的文件名甚至在機器中可以不存在。
?
3.獲取邏輯設備號
??? 在IDL中所有文件輸出和輸入都是在一個邏輯設備號上完成的。一個Open命令的作用是將一個特定的文件(通過其文件名來指定)和一個邏輯設備號相關聯。有128個邏輯設備號可供使用。它們被分成兩類,一類可以直接使用,另一類用Get_Lun和Free_Lun命令獲取和管理。
① 1-99 :可在Open命令中直接使用
② 100-128:通過Get_Lun和Free_Lun命令獲取和管理
3.1 直接使用邏輯設備號??? 要直接使用邏輯設備號,只能在1-99中選擇一個號,并用Open命令使用它。要做的是選擇一個當前沒有使用的號。例如,可用邏輯設備號5來打開當前目錄的子目錄coyote中的galaxy.dat文件,鍵入:
??? IDL>CD,current=thiedir
??? IDL>filename=Filepath(Root_Dir=thisdir,$
??? Subdirectory=’coyote’,’galaxy.dat’)
??? IDL>Openr, 5, filename
?? ?一旦1-99中的某個邏輯設備號分配給一個文件后,它就不能再分配了,直到該邏輯設備號被關閉或退出IDL(這將自動關閉所有打開的邏輯設備號)。
??? 當完成了對邏輯設備號的操作(也就是說,不想再對文件進行讀寫),可用Close命令關閉它,并使其可以重新使用:
??? IDL>Close, 5
3.2 讓IDL管理邏輯設備號
??? 多數情況下(特別在IDL程序中),最好讓IDL管理邏輯設備號??墒褂肎et_Lun和Free_Lun命令完成此項功能。有兩種方法讓IDL返回一個邏輯設備號??梢灾苯邮褂肎et_Lun命令。如:
??? IDL>Get_Lun,lun
??? IDL>OpenR,lun,filename
??? 或者,用帶關鍵字Get_Lun的Open命令來間接完成:
??? IDL>OpenR,lun,filename,/Get_Lun
??? 這個命令運用隱含的Get_Lun命令將作為結果的邏輯設備號存入變量Lun中。這是邏輯設備號最常用的獲取方法,特別是在IDL程序中。(注意,變量名不一定是Lun??梢宰约航o出喜歡的名字。如果打開了幾個文件,就需要幾個不同的名字。)
??? 當完成了對邏輯設備號的操作(也就是說,不想再對文件進行讀寫),可用Free_Lun命令關閉它。如:
??? IDL>Free_Lun,Lun
??? 使用Get_Lun和Free_Lun命令的好處在于不必記住哪個邏輯設備號是可用的或沒被使用的。Get_Lun程序保證返回一個有效的邏輯設備號(假設同時已經打開的文件少于28個)。如果是在過程和函數中打開文件,一般最好使用Get_Lun命令。因為如果直接選擇某個特定的邏輯設備號,不能保證它是可用的或沒有被使用的。
3.3 判斷哪些文件和哪些邏輯設備號相連
?? 使用帶Files關鍵字的Help命令,可以很容易判斷哪些文件和哪些邏輯設備號相連。
?? IDL>Help,/Files
?
4.讀取帶有文件頭的非格式化文件
?? 有時一個文件包含有文件頭信息,讀取里面的數據需要繞過文件頭。
?? 對于頭文件可將其看成是一個字符串。
?? pro readheaderfile,size=size
?????? cd,'c:\'
?????? ; file =dialog_pickfile() ;讀取頭文件目錄
?????? print,file
?????? openr,lun,file,/get_lun ;打開頭文件,將其讀入內存,賦予內部邏輯號lun
?????? header =fstat(lun) ;fstat函數用來統計文件的信息,將其賦予一個結構變量
?????? help,header ,/structure
?????? print,header.size ;結構變量中的size即為文件的大小
?????? size=header.size
?????? free_lun,lun
?? end
?
?? pro readfile?
???????cd,'c:\'?
???????readheaderfile,size =size?
???????;讀取波譜文件?
???????; file1 =dialog_pickfile() ;讀取波譜文件目錄?
???????file1='spect1.txt'?
???????print,file1
?????? openr,lun,file1,/get_lun ;打開文件,將其讀入內存,賦予內部邏輯號lun
?????? point_lun,lun,size ; 定位到size處,有時候需要調整位置,如果數據前有空格也算一個字符
?????? spect =findgen(2,3) ;定義輸出文件的大小,2列3行的文件,可以根據數據大小隨意設置
?????? readf,lun ,spect ; 讀取文件中的數據
?????? print,spect
?????? openw,lun,'c:\spect.txt',/get_lun; 建立一個輸出文件
?????? printf,lun,spect ;將數據保存到data.txt中
?????? close,/all
??? end
5. 讀寫格式化數據
??? IDL在讀寫格式化數據方面有兩種格式化文件之區分:自由文件格式和確定的文件格式。格式化文件有時叫做ASCII文件或者純文本文件。
??? 自由文件格式:自由格式文件用逗號或空白(tab鍵和空格鍵)分開文件中的每個元素,這沒有確定的文件格式正規。
??? 確定的文件格式:確定的格式文件是用格式說明按照給定的規范進行編排的。IDL格式說明和FORTRAN或C程序中的格式說明類似。
5.1 寫自由格式文件
??? 在IDL中,寫一個自由格式文件極其容易。只要用PrintF命令將變量寫入文件即可。這和在顯示窗口上用Print命令打印變量的形式幾乎相同。IDL在寫文件時自動在數據的元素間加入空格。
??? 例如,鍵入下面這些命令,創建數據并寫入文件:
??? IDL>array=FIndGin(25)
??? IDL>vector=[33.6,77.2]
??? IDL>scalar=5
??? IDL>text=[‘array’, ’vector’, ’scalar’]
??? IDL>header=’Test data file.’
??? IDL>created=’created: ’ + SysTime()
??? 接著,將一個邏輯設備號(讓IDL自己選擇一個并放到變量lun中)和特定文件相連來打開文件寫入,鍵入:
??? IDL>OpenW , lun, ’test.dat’,/Get_Lun
??? 最后,將數據寫入文件,并關閉數據文件,鍵入:
??? IDL>PrintF, lun, header
??? IDL>PrintF, lun, created
????IDL>PrintF, lun, array, vector, scalar, text
??? IDL>Free_Lun, lun
??? 用一個文本編輯器打開文件檢查。類似于如下所示:
??? Test data file.
??? created: Tue Nov 28 15:50:58 2000
??? 0.000000 1.00000 2.00000 3.00000 4.00000 5.00000
??? 6.00000 7.00000 8.00000 9.00000 10.0000 11.0000
??? 12.0000 13.0000 14.0000 15.0000 16.0000 17.0000
??? 18.0000 19.0000 20.0000 21.0000 22.0000 23.0000
??? 24.0000 33.6000 77.2000 5
??? array vector scalar
??? 注意:IDL 在數組變量的每個元素間設置空白區,并使每個新變量另起一行開頭。IDL在缺省情況下使用80列寬度。如果需要不同的列寬度,可以用帶Width關鍵字的OpenW命令設置。
?
5.2 讀自由格式文件
??? 許多ASCII文件是自由格式文件。例如,從電子數字表程序中保存的文件大多是自由格式文件。一種特殊的自由格式數據是從鍵盤或標準輸入讀取的數據。
??? 在IDL中,有兩種命令可以讀取自由格式文件。
??? ① Read:讀取從標準輸入或鍵盤上讀入自由格式數據
??? ② ReadF:從文件中讀入自由格式數據
?? ?ascii文件格式屬于自由文件格式的一種,對于其讀取可以采用read_ascii(),返回的是一個結構變量
data=read_ascii('aa.txt',data_start=5);其實數據是從第6行開始的,也就是在讀取的時候跳過頭文件部分
或者:
??? filetemplate =ascii_template(file)
??? data =read_ascii('aa.txt',template=filetemplate)
??? 其他的自由格式文件則直接可用readf讀取
??? readf可以同時讀取多個文件,將其放入到一個文件中。
??? IDL>ReadF, lun, header, data, vector
??? 對于確定格式文件,應用format關鍵字即可。
5.3 讀取自由格式文件的規則
??? 無論是從鍵盤上還是從文件中讀取自由格式的數據,IDL遵循下列7種規則:
?? (1)如果讀入到字符串變量中,那么,在當前行剩下的所有字符都將讀入該變量中。
??? 觀察上面數據文件的第一行,此行內有三個單詞。此項規則意味著,一旦IDL開始為字符串變量讀入數據,那么IDL將一直讀到行末,且不會停止。其原因是在IDL的所有數據類型中,字符串變量可以是任意尺寸的,而且空格符也是ASCII字符。
?? ?打開該數據來讀入,試著只讀入一個單詞,如下:
?? ?IDL>Open, lun, ‘test.dat’, /Get_Lun
?? ?IDL>word = ‘’
? ??IDL>ReadF,lun,word
??? IDL>Print, word
??? 所看到的是整個第一行都被讀入到word變量中。
??? Test data file.
?? (如果想將第一行分解成單個的單詞,可以用IDL的字符串處理程序來完成。)這種可以讀到行末的功能是IDL的一個優點。為什么這樣說呢?首先,將文件指針重置到文件的開頭??捎肞oint_Lun命令實現此項功能。鍵入:
??? IDL>Point_Lun, lun, 0
??? 現在可將數據文件的前兩行讀入到header變量中。鍵入:
??? IDL>header = StArr(2)
??? IDL>ReadF, lun, header
??? IDL>Print, header
??? 這些命令將讀出文件的前兩行,并將文件指針定位到數組的起始處??梢栽谕恍猩贤瑫r輸出頭兩行的內容。
??? Test data file. created: Tue Nov 28 15:50:58 2000
?? (2)輸入數據必須用逗號或空白分隔(空格鍵或tab鍵)。
??? 在test.dat數據文件中所用到的就是這種格式的數據。IDL在數組變量中的每個元素間插入5個空格。
???(3)輸入通過數字變量完成。數組和結構都可作為數字變量的集合。
??? 這意味著,如果正在讀入的變量中,比如說,10個元素,IDL將從數據文件中讀入10個分開的數值。它將采用以下的兩條規則來確定這些數據存在于文件的何處。
?? (4)如果當前讀入行是空的,并且還有變量要求輸入,則讀取另一行。
?? (5)如果當前讀入行不是空的,但是沒有變量要求輸入,則忽略此行剩下的數。
??? 為了解其含意,可鍵入:
??? IDL>data = FltArr(8)
??? IDL>ReadF, lun, data
??? IDL>Print, data
??? 將看到:
??? 0.00000 1.00000 2.00000 3.00000 4.00000 5.00000
??? 6.00000 7.00000
??? 在此例中,IDL從文件中讀入8個分開的數據值。當讀取到第一行數據的末端時,它自動進入到第二行(規則4),因為還有更多的數據要求讀入。當數據讀入到第二行的中部時,規則5起作用了。如果現在還要讀入更多的數據,那將從數據的第三行開始,因為第二行的其它部分被忽略了。鍵入:
??? IDL>data = FltArr(3)
??? IDL>ReadF, lun, vector3
??? IDL>Print, vector3
??? 將看到:
??? 12.0000 13.0000 14.0000
??? 變量vector3包含的數值為12.0、13.0和14.0。現在,文件指針定位在文件中的第四數據行上(規則5)。
?? (6)盡量將數據轉換為變量所希望的數據類型。
??? 要了解這是什么意思,將第四、第五行數據讀入到一個字符串數組,以便讓文件指針定位在文件中的第六行數據(即起始數值為33.6000的那行)。鍵入:
??? IDL> dummy = StrArr(2)
??? IDL> ReadF, lun, dummy
??? 假設想讀入兩個整型值。IDL盡量將數據(在此情況下,為浮點數)轉換為整型。
鍵入:
??? IDL> ints = IntArr(2)
??? IDL> ReadF, lun, ints
??? IDL> Print, ints
??? 將看到:
??? 33 77
????注意,浮點數被簡單的截取成整數。在轉換處理過程中并沒有采用四舍五入的規則來保證最接近的整數值。
7. 復數數據必須有實數和虛數兩部分,用逗號分隔,并用括號括起來。如果僅僅提供了單個數值,它將被認為是實數部分,而虛數設置為0。例如,可通過鍵盤讀入復數數據:
??? IDL>value = ComplexArr(2)
??? IDL> Read, value
??? : (3, 4)
??? : (4.4, 25.5)
??? IDL> print, value
??? 在結束這部分學習之前,確保已將test.dat文件關閉。鍵入:
??? IDL>Free_Lun, lun
??? 5.4 讀寫自由格式文件的實例
??? 學會用IDL讀寫數據最容易的方法是看一些實例。下面實例說明在讀入文件頭、處理以列排列的數據以及處理已讀入IDL的數據這些方面的常用IDL技巧。
??? 讀一個簡單數據文件
??? 從讀剛創建的test.dat文件中的數據開始。首先,創建用于讀文件中數據的變量。
??? IDL>header=strarr(2) ; two header lines.
??? IDL>data=fltarr(5,5) ; floating point array.
??? IDL>vector=intarr(2) ; two-element integer vector.
??? IDL>scalar=0.0 ; floating-point scalar.
??? IDL>string_var=’’ ; a string variable.
??? 注意,此時數據變量將是5*5的數組。而在文件中是以25個元素的矢量保存的。用這種方法讀入數據相當于讀入25個元素的矢量,并將其重新格式化為5*5的數組。記住IDL中的數據是按行存儲的。
??? 根據規則一,不能將文件末端的一行文本讀到三個元素的字符串數組中。不得不將其讀入單個字符串變量,然后用IDL的字符串處理命令將該文本字符串分解到后續的變量中。
??? 可立即從文件中讀出所有數據,鍵入:
??? IDL>openr, lun, ’test.dat’, /Get_Lun
??? IDL>ReadF, lun, header, data, vector, scalar, string_var
??? IDL>free_Lun, lun
??? 要將包含文件末行文本的字符串變量轉換成三個元素的字符串數組,首先要將變量前后兩頭的空白字符除去。鍵入:
??? IDL>thisstring=strtrim(string_var,2)
??? 有時若將字符串轉換成字節型數組,字符串的處理就會容易些??梢韵忍幚碜止澬蛿到M,最后再將其轉換成字符串。當然也可使用其它方法,但是這種方法在這里更好一些。
??? IDL>thisarray=Byte(thisstring)
??? IDL>help,thisarray
??? 這是19個元素的字節型數組。要知道空格的ASCII碼字符,可用IDL查出:
??? IDL>blank=Byte(“ ”)
??? IDL>print,blank
??? IDL>help,blank
??? 注意,Byte命令處理一個字符串后的返回值總是一個數組。在此例中,是一個元素的數組。為了以后不至于混淆,將其轉換成一個數值。
??? IDL>blank=Blank[0]
??? 輸出空白字符的ASCII碼值是32。
??? 可用Where命令顯示字節型數組中的空白字符。
??? IDL>vals=Where(thisarray EQ blank)
??? 最后,將字符串轉換成三個元素的數組。
??? s=strarr(3)
??? s[0]=string(thisarray[0:vals[0]-1])
????s[1]=string(thisarray[vals[0]+1:vals[1]-1]
??? s[2]=string(thisarray[vals[1]+1:*]
?
5.5 寫列格式數據文件
??? 在文件中數據按列儲存是不稀奇。需要了解如何用IDL讀寫這種數據。IDL將會給粗心的程序員一個驚喜。要知道究竟是怎么回事,可以寫一個列格式數據文件。用下列命令將數據讀入IDL:
??? IDL>data=LoadData(15)
??? 這個數據是一個有三個字段的結構:lat, lon和temp。每個字段都是41個元素的浮點矢量。可用如下命令從結構中提取矢量:
????IDL>lat=data.lat
??? IDL>lon=data.lon
??? IDL>temp=data.temp
??? 接著,打開一個寫入數據文件,鍵入:
??? IDL>OpenW,lun,’column.dat’, /Get_Lun
??? 需要將三列數據寫入這個文件,通過自由格式輸出。這可以在一個循環中完成。
??? IDL>printf, lun, ’column data: lat, lon, temp’
??? IDL>FOR j=0, 40 DO printf, lun,lat[j], lon[j], temp[j]
??? IDL>free_lun, lun
??? column.dat文件的前四行應如下:
??? Column data: lat, lon, temp
??? 33.9840 –86.9405 36.9465
??? 26.2072 –121.615 20.1868
??? 42.1539 –103.733 231.604
5.6?讀列格式數據文件
??? 到目前為止一切正常。當試著將列格式數據讀入 IDL時問題就出來了??赡艿冒慈缦虏僮觥J紫?#xff0c;創建要讀入數據的變量。
??? IDL>header=’’
??? IDL>thislat=fltarr(41)
??? IDL>thislon=fltarr(41)
??? IDL>thistemp=fltarr(41)
??? 打開column.dat文件讀首行:
??? IDL>OpenR, lun, ’column.dat’ ,/Get_Lun
??? IDL>ReadF, lun, header
??? 由于是用一個循環將數據放進文件的,所以也可能會用一個循環從文件中將數據讀出。
??? IDL>FOR j=0, 40 DO ReadF, lun, thislat[j], thislon[j], thistemp[j]
??? 但這不奏效。雖然上面的命令沒有錯誤,但沒有數據讀入變量(如打印變量值,它們將是零)。其原因是IDL中有一個嚴格的規則,即不能帶下標的變量來讀入內容。原因是IDL 將帶下標的變量作為值而不是作為變量的引用傳遞給象ReadF這樣的IDL 程序。以數值傳遞的數據不能在被調用的子程序中改變,因為被調用的子程序只是獲得該數據的備份,而不是獲得該數據的指針。要改變這種屬性需要對IDL進行大改,然而這是不可能的。
??? 有兩種方法解決這個問題。第一種是將數據讀入一個循環中的臨時變量。這種方法最好是運用文本編輯器將命令輸入文件中來完成,因為很難在IDL命令行上編寫多行循環??捎肞oint_Lun命令將文件指針返回到數據文件的起始處。
????IDL>Point_Lun, lun, 0
??? 在文本文件loopread.pro中輸入下列命令。
??? temp1=0.0
??? temp2=0.0
??? temp3=0.0
????ReadF, lun, header
??? FOR j=0, 40 DO BEGIN
?????? ReadF,lun, temp1, temp2, temp3
????? ?Thislat[j]=temp1
?????? Thislon[j]=temp2
?????? Thistemp[j]=temp3
??? ENDFOR
??? END
??? 執行文本文件中的代碼:
??? IDL>.Run loopread
??? 將原始矢量的值和剛讀入矢量的值打印出來,將發現它們是相同的。例如:
??? IDL>Print, lat, thislat
??? 雖然這個方法奏效,但它不是最好的方法。主要是因為它用了一個循環,循環在IDL中很慢。41次循環的速度也許無所謂,但如果是41,000次循環,執行速度將是個麻煩問題。
??? 較好的方法是將數據一次性讀到3*41的數組內,然后在用IDL提供的數組處理命令將矢量從這個較大數組中提出。要知道這是如何實現的,可用下面命令將數據文件指針返回到頭:
??? IDL>Point_Lun, lun, 0
??? 接下來,將數據一次性讀到3*41的浮點數組:
??? IDL>header=’’
??? IDL>array=fltarr(3,41)
??? IDL>ReadF, lun, header, array
??? 用數組下標將大數組的矢量分離出來:
??? IDL>thislat=array[0,*]
??? IDL>thislon=array[1,*]
??? IDL>thistemp=aarry[2,*]
??? IDL>Free_lun, lun
??? 注意,這些新的矢量是列矢量(也就是說,是1*41的二維數組。)鍵入:
??? IDL>Help, thislat, thislon, thistemp
??? 要使這些列矢量轉換成更熟悉的行矢量,可用Reform命令將1*41 的數組轉換成41*1的數組。當多維數組的最后維為1時,IDL 便舍棄這個維。鍵入:
??? IDL>thislat=ReFORm(thislat)
??? IDL>thislon=ReFORm(thislon)
??? IDL>thistemp=ReFORm(thistemp)
??? IDL>Help, thislat, thislon, thistemp
5.7?創建讀列格式數據的模板
??? 由于許多人都用有列格式數據文件,IDL5引進了一個新的程序以便更容易讀此類數據文件。提供幫助的是兩個新命令:ASCII_Template和Read_ASCII命令。ASCII_Template命令是個組件程序,可以引導讀者按步驟定義自己的列數據??梢越o每列數據命一個名字,告訴IDL數據類型,甚至可以跳過一些列。運行該程序的結果是用結構變兩的形式生成了數據文件的模板。這個模板可以傳給Read_ASCII命令,數據就會按模板規范來讀取。其結果是一個根據模板的規范讀出來的帶有字段名的IDL結構變量。要知道它如何運用到上面文件中,可鍵入:
??? IDL>fileTemplate=ASCII_Template(‘column.dat”)
按照出現在顯示器上的組件對話框模式指導進行操作。其形式有三頁,在第一頁上可以看到數據文件的樣本行,左邊有它們的行號。在標有Data Starts at Line的文本組件中:輸入2。這允許在文件中跳過一行的文件頭。在組件的右下角選擇Next按鈕進入下一頁。
??? 注意在這頁里,每行的字段數列出的是三,并可選擇White Space按鈕作為數據分隔符。若信息正確,就點擊Next 按鈕進入最后一頁。
??? 在這頁中,數據組可以被命名并且可以被指定數據類型。如果想在數據中跳過一列或多列,可在界面的右上角的下拉式列表框Type中將其設為Skip Field類型。通過界面右上角的Name文本組件,將三個字段分別命名為Latitude,Longitude和Temperature。這些字段都是浮點類型。
??? 當完成命名和選擇數據列的數據類型后,選擇界面上的Finish按鈕。運行結果是一個用于描述文件中數據的IDL結構變量,它們可被用作Read_ASCII命令的輸入。
??? IDL>help, fileTemplate, /structure
??? 要讀文件中的數據,可使用Read_ASCII命令。
??? IDL>data = Read_ASCII (‘column.dat’, Template= fileTemplate)
??? 數據立刻被讀取,結果是包含三個字段latitude, longitude, temperature的IDL結構變量。
??? IDL>Help, data, structure
??? 如果要提出結構中的矢量,可鍵入:
??? IDL>thislat=data.latitude
??? IDL>thislon=data.longitude
??? IDL>thistemp=data.temperature
??? ASCII_Template和Read_ASCII命令既可用于自由格式的數據文件,也可用于下面將要討論的確定格式的數據文件。
5.8 用確定的文件格式寫入
??? 讀寫確定文件格式可同樣用ReadF和PrintF命令,它們剛才已用于自由格式文件,但現在文件格式已由Format關鍵字明確聲明。(在讀寫標準輸入和輸出時,也可將Format關鍵字用于Read 和Print命令)。
????Format關鍵字的語法和在FORTRAN程序中使用的格式規則類似。盡管格式規則很復雜,這兒卻有許多共同之處。如果使用過FORTRAN代碼來讀寫數據的話,便會很快地熟悉它們。
(1)?一些共有的格式說明符
??? 在IDL中有許多格式說明符,有一些是共有的。如矢量數據的定義:
??? IDL>data=Findgen(20)
??? ① I 修飾整型數據。
??? 將數據按整數輸出,以每個兩位,每行 5個,每個之間有兩個空格的形式打出:
????IDL>thisFormat=’(5(I2,2x),/)’
??? IDL>Print, data, Format=thisFormat
??? ② F 修飾浮點數據。
??? 將數據按浮點數輸出,以小數點后兩位,每行一個的形式打出。(這個數要為小數點留出一位)
??? IDL>thisFormat=’(f5.2)‘
??? IDL>Print,data,Format=thisFormat
??? ③ D 修飾雙精確數據。
??? 將數據按雙精度輸出,按每行寫5個,每個數之間有4個空格,小數點右邊有10位的形式打出。
????IDL>thisFormat=’(5(D13.10, 4x))’
????IDL>Print, data*3.2959382, Format=thisFormat
??? ④ E 用科學記數法描述浮點數據(如:116.36E4)
??? IDL>thisFormat=’(E10.3)’
??? IDL>Print, data*10E3, Format=thisFormat
??? ⑤ A 描述字符型數據。
??? 將數字轉換成字符串,并以四個字符長的字符串形式寫出,每個字符串用兩個空格分開,每行4個字符串:
??? IDL>thisFormat=’(4(A4, 2x))’
??? IDL>Print,StrTrim(data,2), Format=thisFormat
??? ⑥ NX 跳過n個空格字符。
(2)寫用逗號分隔的確定格式數據文件
??? 有時數據文件必須用確定格式書寫,以方便它們被其它軟件讀取。用逗號分隔的數據文件就是這類文件的典型代表。例如,要把上面讀到的數據寫成此類文件。下面就是如何實現??捎肍ormat.dat作為寫入的文件名,鍵入:
??? IDL>OpenW, lun, ’Format.dat’, /Get_Lun
??? 創建一個逗號字符串變量,如:
??? IDL>comm.=’ , ‘
??? 以確定格式寫出文件,用10位寬并有三位小數的浮點數,后接一個逗號和兩個空格,鍵入:
??? IDL>thisFormat=’(F10.3, A1, 2x, F10.3, A1, 2x, F10.3)’
??? IDL>FOR j=0,40 DO PrintF,lun, thisLat[j],comma,$
??? thisLon[j],comma,thisTemp[j],Format=thisFormat
??? IDL>Free_lun,Lun
??? 數據文件前三行如下所示:
??? 48.000, -121.128, 36.946
??? 44.843, -108.133, 163.027
??? 29.865, -109.668, 89.870
(3)讀出用逗號分隔的確定格式文件
??? 要讀取剛創建的確定格式數據文件,鍵入:
??? IDL>OpenW, lun, ’Format.dat’, /Get_Lun
??? IDL>thisFormat=’(2(F10.3, 3X), F10.3)’
??? IDL>array=Fltarr(3, 41)
??? IDL>ReadF, lun, array, Format=thisFormat
??? IDL>Free_lun, lun
??? 這很簡單,注意只要按上面的格式把逗號當作空格跳過即可。
(4)從字符串中讀取格式數據
??? ReadS是一個有用的IDL命令,可以從字符串變量而不是從文件中為自由格式或確定格式讀取數據。ReadS運用了和命令Read和ReadF相同的讀取格式數據規則。也就是說,使用ReadS 就象從數據文件中讀取一樣,所不同的是所讀的對象是一個字符串變量。
??? 當大量信息需從文件頭部讀取時,此命令特別有用。例如,假設ASCII 數據文件的第一行說明了數據文件的行數和列數,隨后是采集數據的時間。例如:
??? 10 24500 12 June 1996
??? 此文件頭可以從文件中讀取,并且可創建一個大小正確的數組來讀取數據。如下:
??? firstLine=’’
??? ReadF,lun,firstLine
??? columns=0
??? rows=0
?? ?date=’’
??? ReadS,firstLine,columns,rows,date
??? dataArray=FltArr(columns,rows)
6.讀寫非格式化數據
?? ?遲早,數據會越來越多。若這樣,就要開始思考更好的數據儲存方法。非格式化數據(有時叫二進制數據)比格式化數據緊湊得多,經常用于大數據文件。有兩種命令讀寫非格式化數據,它們與早期用來讀取格式數據文件的ReadF和 Print 命令等效。它們是ReadU和WriteU命令。
??? 非格式化數據文件基本是以一長串的二進制字節存在文件中。這些字節的含義(也就是說,這些字節如何翻譯成特定數據類型和結構的)很艱難的描述的,除非剛開始就知道文件寫入的是什么內容。在文件里面,各字節都很相似。將字節讀入正確類型和結構的變量中就可理解了。原則上這很容易做到,因為多數數據類型有給定的字節長度。例如,每個浮點值有4個字節。IDL整數有兩個字節,等等。
??? 要讀取非格式數據文件,簡單定義變量,打開文件讀取,并用ReadU命令將字節一個接一個地讀入變量中。如果給定了變量的數據類型和組織結構,每個變量按其要求從文件中讀出相應的字節數。例如,一個5個元素的浮點矢量將從文件中讀取五(元素數)乘四(一個浮點值的字節數)共二十個字節。
6.1 讀取非格式化圖像數據文件
??? 例如,假設想讀取儲存在coyote子目錄下的幾個非被格式化圖像數據文件中的一個。這些文件碰巧包含的是字節型數據,但它們也能容易地包含整數與浮點數。下面的一些命令被用來打開其中之一,galaxy.dat文件。星系圖像的字節已被組織成一個256*256字節的數組。(這個代碼已假定coyote子目錄存在于IDL主目錄中。)
??? IDL>filename=Filepath(Root_Dir=!Dir, $
??? Subdirectory=’coyote’,’galaxy.dat’)
??? IDL>OpenR, lun, filename, /Get_Lun
??? 此幅圖像的結構為一個256*256的數組。如果事先不知道這些,為正確地讀取這個數據,將會花費很大的精力。因為在數據文件里沒有信息提示這些字節是如何被組織起來的。
??? 在研究非格式化數據文件之前,如果不知道它有多大,那么只有一件事情要做。這也就是它包含多少字節。例如,FStat(文件的狀態)命令能告知文件的字節數。
??? IDL>fileInfo=Fstat(lun)
??? IDL>Print,fileInfo.size
??? 65536
??? 在這個文件里有65536個字節,但這沒有告知這個數據的結構是怎樣組織的。例如,這些字節能被組成128*512的二維數組,也可以被組成64*64*16的三維數組。沒有辦法知道這些。絕望的程序員有時嘗試用各種數組組合來顯示數據。如果這個看起來不對,就試著用另外一個,等等。
??? 在此例子中,這些數據被組成256*256字節型數組。因此圖像變量能夠這樣設定:
??? IDL>image=BytArr(256,256)
??? 現在,從文件里讀取數據,然后關掉文件,如下:
??? IDL>ReadU, lun, image
??? IDL>Free_Lun, lun
??? 顯示數據,鍵入:
??? IDL>Window,Xsize=256,Ysize=256
??? IDL>Tvscl, image
6.2 寫非格式化圖像數據文件
??? 假設在圖像上進行了一些處理,想將結果保存在另一個數據文件里。例如,在圖像上進行了一個Sobel邊界增強操作,如下:
??? IDL>edge=Sobel(image)
Sobel操作不僅可以幫助圖像增強它的邊緣,而且被返回的圖像不再是字節類型。事實上,它是整數數據,鍵入:
??? IDL>Help, image, edge
??? 在IDL中整數占兩個字節,因此如果這個數據被寫入一個數據文件,這個文件的大小將會是原來的字節型數據文件的兩倍。這些對于那些試圖讀取處理后的圖像數據文件的人來說可能有些混淆。所以可以考慮在文件里給出一些信息,告訴用戶關于這種數據的相關類型以及怎樣組織的。這個文件信息可以按如下定義:
??? IDL>fileInfo =’Sobel Edge Enhanced, 256 by 256 INTEGERS’
??? 這些字符串可以在文件里寫在圖像數據的前面。
??? 但是,字符串fileInfo也是一串字節。在此例中,它是一個有31個字節的字符串。如果不知道關于此非格式化文件的這一點,以后從文件里讀取數據將會非常困難。例如,設或許認為信息字符串是30個字節長。這樣,在讀完文件信息字符串之后,繼續讀出的每一個整數(兩個字節)將會完全是錯誤的。
??? 為避免這么多的限制,大多數非格式化數據文件的文件頭有著固定的大小(通常是256的倍數)。例如,假設決定所有的圖像文件都有一個512個字節的頭文件??捎肐DL 里的Replicate和String命令創造一個有512個字節長的空格字符串。
??? IDL>header = String (Replicate (32B, 512))
??? 字節值32是一個空格字符的ASCII值。把文件信息字符串插入這個長一點的文件頭字符串中,從而建立具有一個正確尺寸的頭文件??梢杂肐DL里的StrPut (把一個字符串放進另外一個字符串)命令。如下:
??? IDL>strPut, header, fileInfo, 0
??? 最后,將文件頭和數據寫入一個新的非格式化數據文件中。如下:
??? IDL>OpenW, lun, ‘process.dat’
??? IDL>WriteU, lun, header, edge
??? IDL>Free_Lun, lun
??? 當字符串被寫進非格式化的文件之時,也就相當于,字符串含多少個字符,就有多少個字節被寫進文件。
6.3 讀取帶有文件頭的非格式化數據文件
??? 假設想讀取上面剛建立的文件,里面有512個字節的頭文件信息,緊接著是256*256*2個字節的圖像數據。可以將頭信息看成是一個字符串,因為它含有關于文件里保存的數據類型的文本信息。
??? 對于格式化的數據,文件頭的變量可以被創建成空一個字符串或一個空字符串數組,以便數據文件的全部行能一次讀入到文件頭變量。對于非格式化的文件這是不可能的。事實上,非格式化字符串數據的規則是當從文件里讀取字符串時,僅僅只是讀取確定個數的字節去填滿該字符串目前的長度。這樣,一個文件頭被定義為一個空字符串,將不會從非格式化的文件里讀出什么。
??? 這意味著在從文件中讀取字符串之前,必須知道正在讀的字符串長度。在剛創建的process.dat文件里,文件頭有512個字節長??梢杂肧tring和Replicate命令建立一個合適長度的空白字符串去讀入,象前面那樣。但是更容易的方法是把文件頭讀進一個字節型數組變量,然后把它轉變成一個字符串。鍵入:
??? IDL>OpenR, lun, ‘process.dat’, /Get_Lun
??? IDL>header =BytArr(512)
??? IDL>ReadU, lun, header
??? IDL>Print, String(header)
??? Sobel Edge Enhanced,256 by 256 INTEGERS
??? 從這條信息里面,就能夠建立正確的數據數組,并從文件里讀出圖像數據并顯示它們。如下:
??? IDL>edgeImage =IntArr(256,256)
??? IDL>ReadU, lun, edgeImage
??? IDL>Free_Lun, lun
??? IDL>Window, XSize=256,YSize=256
??? IDL> TV, edgeImage
6.4 非格式化數據文件的一些問題
??? 不幸的是,雖然處理非格式化的數據較方便,但同時在使用這種數據是也有一些相關的問題。首先,非格式化的數據與機器類型有很大關系。在SUN計算機上寫的數據,如果不做任何處理的話,在SGI或者HP計算機上經常讀不出來,而在PC或者Macintosh計算機上是肯定讀不出來的。(ByteOrder命令能夠用來解決許多這類問題。IDL5.1版將新的Swap_If_Big_Endian和Swap_If_Little_Endian關鍵字引入到Open命令中,可用于在各種各樣的機器結構上編寫代碼來讀取二進制數據。)
??? 為了能在不同的機器結構上傳遞非格式化數據,IDL支持XDR(eXternal Data Representation,外部數據表示)文件格式。XDR格式是Sun Microsystems創建的公用的數據格式。在幾乎所有的現代化計算機上都可用。它在二進制文件里存儲了少量的元數據(數據本身的一些附加信息)。但是XDR文件仍然很簡潔。
如果文件是用XDR非格式化的形式寫的,數據文件在計算機之間很容易傳遞。換句話說,XDR非格式化文件成為跨機器結構的文件格式。
??? 要讀寫XDR格式的文件,必須用XDR關鍵字打開。例如:把上面的process.dat文件寫成XDR文件,可以鍵入:
??? IDL>OpenW, lun, ‘process.dat’, /Get_Lun, /XDR
??? 常規的WriteU命令用來把數據寫進文件:
??? IDL>WriteU, lun, header, edge
??? IDL> Free_Lun, lun
??? 在XDR文件里字符串的長度被存儲起來,并隨著字符串本身一起被恢復。這意味著不必要象一般的非格式化文件那樣,每次都初始化一個正確長度的字符串變量。例如,打開讀取XDR文件里的信息,可以鍵入:
??? IDL>OpenR, lun, ‘process.dat’,/XDR
??? IDL> thisHeader = ‘’
??? IDL> thisData =IntArr(256,256)
??? IDL> ReadU, lun, thisHeader, thisData
??? IDL> Free_Lun, lun
6.5 用關聯變量存取非格式化數據文件
??? 大型的非格式化數據文件通常都有一系列的重復單元組成。例如,一個衛星每隔半小時就拍攝一幅512*600像素的浮點圖像,并將這些圖像一個接一個地存儲在一個數據文件里,這個文件每隔一定的時間被下載一次。在數據文件里包含50-100M的數據是很尋常的。一個IDL關聯變量通常是處理這種數據形式的最好方式(有時候是唯一的方式)。
??? IDL關聯變量是把一個IDL數組或結構變量的組織結構映射到數據文件的內容上。文件被看作是這些重復單元的一個數組。第一個單元的索引號是0,第二個單元的索引號1等等。關聯變量不象常規變量那樣將整個數據組都存儲在內存里。而是當一關聯變量被引用時,IDL僅對需要的部分數據執行相關的輸入或輸出請求,這部分數據就是要讀入內存的。
6.5.1 關聯變量的一些優點
?? ?關聯變量有以下幾個優點:
?? ?① 當該變量被用于表達式時,才產生文件的輸入和輸出動作。不需要單獨的讀或寫命令。
?? ?② 數據集的大小不受內存容量的限制,因為有時它可處理大型的數據集。對于物理存儲器來說是太大的數據,通過把此數據分成塊就能很容易地處理。
??? ③ 不必提前聲明用于映射該數據的數組或結構的數量。
??? ④?關聯變量是效率最高的I/O形式。
6.5.2 定義關聯變量
??? 定義和使用關聯變量,可按通常的方式打開數據文件,然后用Assoc命令創建關聯變量。例如,打開位于IDL主目錄下的coyote 子目錄中的abnorm.dat文件。
??? IDL> filename = Filepath(Subdir=’coyote’, ‘abnorm.dat’)
??? IDL> OpenR, lun, filename, /Get_Lun
??? 這個文件里含有16幅圖像或16幀畫面,每幅都是64*64個字節型數組。為這些數組創建關聯變量:
??? IDL> image = Assoc(lun, BytArr(64,64))
??? Assoc命令的第一個參數是與image變量相關聯的文件的邏輯設備號。第二個參數是文件中被重復的單元的描述。
??? 這些文件在重復文件單元前通常有文件頭信息,盡管此文件沒有。如果這樣的話,Assoc命令的第三個定位參數是給定文件頭的大小或文件頭在文件中的偏移量。例如,假設abnorm.dat文件的前4096個字節是文件頭信息,并且希望跳過文件頭,那么Assoc命令可以被寫成這樣:
??? IDL> image2 = Assoc(lun, BytArr(64,64), 4096)
??? 注意,現在有兩個變量,image和image2,與同一個數據文件關聯。這在IDL中完全合法,事實上,這對于存取重復單元不一致的非格式化數據文件是一種好辦法。通過改變在文件中的偏移量,可以用關聯變量來實現隨機讀寫數據。
??? 顯示上面image變量里的第五幅圖像或畫面,鍵入:
??? IDL> TvScl, image (4)
??? 從數據文件里把數據讀進一個臨時變量,在其被顯示后,被IDL刪除。沒有顯式的ReadU命令,也不需要常規情況下IDL處理這幅圖像所需要的永久內存。如果想從關聯變量中創建一個變量,可按通常的方式建立這個變量。例如,可以鍵入:
??? IDL> image5 = image (4)
??? IDL> TV, Rebin (image5, 256,256)
??? 數據文件里重復單元的形式沒有必要只是一個簡單的二維圖像數組。它可以是一個復雜的結構。例如,每一個重復單元可以包含128個字節的文件頭,兩個100個元素的浮點型矢量和一個100*100的整型數組。如果是這樣,可以建立一個文件關聯變量。鍵入:
??? OpenR, 10, ‘example.dat’
??? Info = BytArr (128)
??? xvector = FltArr (100)
??? yvector = FlatArr(100)
??? data = IntArr (100,100)
??? struct = {header: info, x: xvector, y: yvector, image: data}
??? repeatingUnit = Assoc (10, struct)
??? 因為映射到此數據文件相的變量是一個結構變量,因此在它的引用被刪除之前,必須對此結構變量進行臨時拷貝。例如,顯示文件第三個重復單元的圖像部分,可以鍵入:
??? TempVariable = repearingUnit (2)
??? TvScl, temPvariable.image
??? 按照通常的方式,可以用Free_Lun或Close命令將關聯變量和文件之間的聯系關閉。如下:
??? Free_Lun, lun
??? Close, 10
?
7.讀寫通用格式文件
?? IDL能夠讀寫許多常用的數據文件格式,如下表所示。一般情況下通過用IDL語言寫的庫程序或動態連接模塊(DLM)來完成的,DLM在運行時可以添加到IDL中。CDF、netCDF和HDF文件格式是著名的科學數據格式,有它們自己的IDL接口和庫程序。
?
| 文件格式 | 讀此類文件的IDL程序 | 寫此類文件的IDL程序 |
| BMP | Read_BMP | Write_BMP |
| CDF | 參考CDF庫 | 參考CDF庫 |
| DICOM | IDLffDICOM對象 | IDLffDICOM對象 |
| DXF | IDLffDXF對象 | IDLffDXF對象 |
| GIF | Read_GIF | Write_GIF |
| HDF | 參考HDF庫 | 參考HDF庫 |
| HDF-EOS | 參考HDF庫 | 參考HDF庫 |
| Interfile | Read_Interfile | 無 |
| JPEG | Read_JPEG | Write_JPEG |
| netCDF | 參考netCDF庫 | 參考netCDF庫 |
| PICT | Read_PICT | Write_PICT |
| PBM/PPM | Read_PPM | Write_PPM |
| PBM/PPM | Read_PPM | Write_PPM |
| PNG | Read_PNG | Write_PNG |
| PostScript | 無 PS或打印設備 | ? |
| Sun Rasterfiles | Read_SRF | Write_SRF |
| SYLK | Read_SYLK | Write_SYLK |
| TIFF/GeoTIFF | Read_TIFF | Write_TIFF |
| WAVE | Read_WAVE | Write_WAVE |
| X11-bitmap | Read_X11_Bitmap | 無 |
| XWD | Read_XWD | 無 |
7.1 創建彩色GIF文件
??? GIF文件常被用來在萬維網上發布圖形信息。如果想和同事共享圖形結果,遲早要讀寫GIF文件。
??? 要看其是如何完成的,可裝入一些數據,然后在圖形窗口中顯示這些數據。鍵入:
??? IDL> Window, XSize=300, YSize=300
??? IDL> data= LoadData (1)
??? IDL> TVLCT, [100,255,0], [100,255,255], [100,0,0], 0
??? IDL> Plot, data, /NoData, Color=2, Background=0
??? IDL> OPlot, data, Color=1
7.2 寫GIF文件
??? 下面的命令生成一個大小為300*300像素的GIF文件。首先,將圖形窗口的內容復制到一個2D字節型圖像變量中。如果在使用8位顯示器,TVRD命令可用來實現這個目的。
?? ?IDL> image = TVRD ()
?? ?如果正在16位或24位彩色顯示器運行IDL,那么需要用TVRD命令獲取一幅24位的圖像,然后用Color_Quan命令將它壓縮成一幅帶有正確色彩表矢量的2D圖像,命令如下。只有是在16位或24位顯示器上運行IDL,才用下面的命令代替上面的命令:
??? IDL> image = TVRD (True=1)
? ? IDL> image = Color_Quan (image24, l, r, g, b)
??? 假如已經有一個2D字節型數組,就沒有必要再拷貝圖形窗口。
??? GIF文件格式要求將色彩表隨圖像數據一起存儲到GIF文件內。如果使用8位顯示器,那么用TVCL命令和Get關鍵字就可以得到由紅、綠、藍三種顏色矢量組成的當前色彩表:
??? IDL> TVCL, r, g, b, /Get
??? 假如正在16位或24位的顯示器上運行作,沒有必要鍵入上面的命令。可以在上面Color_Quan命令里得到相關圖像的色彩表矢量。
??? 色彩矢量必須是256個元素。如果在8位顯示器上運行IDL,這些矢量可能就沒有這么長,但是不必擔心。如果在寫GIF文件時這些色彩矢量不夠長的話, IDL將會加長色彩矢量。如果想充分利用256種顏色,可考慮在Z圖形緩沖區裝載色彩表,然后得到顏色矢量,缺省情況下可獲得256種顏色。參考125頁的“Z圖形緩沖區中的圖形顯示技巧”。
最后,用Write_GIF命令將圖像和顏色矢量寫進名為test.gif 的GIF文件:
??? IDL> Write_GIF, ‘test.gif’, image, r, g, b
??? 以上就是所有要做的。沒有必要獲取邏輯設備號或其它東西。所有這些細節都是IDL庫程序Write_GIF命令來處理的。如果對具體如何實現感到好奇的話,可以檢查源代碼。
??? 如果讀者有某個應用程序能打開和讀取GIF文件,試著讀一下剛建立的文件。許多萬維網的瀏覽器都支持讀取GIF文件。看一下,如果瀏覽器有一個Open File按鈕,用它試試看能否讀取這個GIF文件。
7.3 讀GIF文件
??? 要讀剛建立的GIF文件,可按下面簡單地用Read_GIF命令讀GIF文件里的圖像和顏色矢量。
?? ?IDL> Read_GIF, ‘test.gif’,thisImage, rr, gg, bb
??? 清除圖形窗口,裝載一個灰色級調色板,可以看到將發生什么。鍵入:
??? IDL> Erase
??? IDL> LoadCT, 0
??? 現在,顯示剛從文件里讀取的圖像,如下:
??? IDL> TV,thisImage
??? 有時候在圖形窗口里什么都看不到,這是因為GIF圖像使用的顏色還沒有裝入。必須裝載和GIF圖像相關的色彩表,以便這個圖像能夠正確地顯示。鍵入:
??? IDL> TVCT, rr, gg, bb
??? 將在顯示窗口里看到原始圖像。
??? 假設在16位或24位上的顯示器上,必須關掉顏色分解。為了看到正確的顏色,必須在裝入顏色表矢量之后重新顯示這個圖像。
??? IDL> Device, Decomposed=0
??? IDL> TV, thisImage
7.4 創建彩色JPEG文件
??? JPEG格式被稱為有損壓縮格式。也就是說,當圖像數據被壓縮報存到文件時,數據的一些信息內容會被丟失,并且不能被恢復。壓縮比例,丟失的信息量以及輸出圖像的質量通常可用質量索引值來設定,質量索引值的范圍從0(丟失許多信息內容的,質量差)到100(很少或根本就沒有信息丟失,質量好)。
??? 通常,質量索引值被設置為75,即保證一個適當的壓縮比,沒有丟失很多信息且圖像質量損失不大。
??? 一幅彩色JPEG圖像一般是24位的圖像。也就是說,這個圖像是3D字節型數組。在這個數組中,維數之一將為3。這個維數的位置將決定圖像是隔像素掃描(3, m, n),隔行掃描(m, 3, n),還是隔波段掃描(m, n, 3)。在很多情況下,所擁有的圖像是8位的圖像,而不是24位的圖像,希望將其轉變成一幅JPEG文件。例如,圖像可能是圖形窗口的屏幕轉儲,象上面的GIF例子一樣。下面是如何從8位圖像創建隔像素掃描的24位圖像的實例。
??? 首先,打開一個圖形窗口,在色棒旁顯示一幅圖像。代碼中的TVImage和Colorbar命令在已下載的本書配套程序中。鍵入:
??? IDL> Window, Size=400,Ysize=300
??? IDL> LoadCT, 3
??? IDL> image = LoadData(7)
??? IDL> TVImage, image, Position=[0.1, 0.1, 0.75, 0.9]
??? IDL> Colorbar, Position=[0.8, 0.1, 0.86, 0.9], /Right, $
??? /Vertical, Division=5, Format=’(F5.1)’
7.5 寫JPEG文件
??? 接下來,對圖形窗口進行拍照,獲得圖形輸出的一幅二維圖像,并用這幅圖像創建隔像素掃描的24位圖像。24位圖像是通過用顏色表矢量建立的,實質上是將顯示圖像的顏色進行分離。IDL代碼如下:
??? IDL> image = TVRD()
??? IDL> image = BytArr(3, 400, 300)
??? IDL> TVLCT, r, g, b, /Get
??? IDL> image3D[0, *,*]=r[image]
??? IDL> image3D1, *,*] =g [image]
??? IDL> image3D[2, *, *] = b[image]
??? 注意,如果是在16位或24位顯示器上,用一個簡單的命令就可以得到24位的圖像。不需要鍵入上述的命令,只需鍵入:
??? IDL> image3D=TVRD(true=1)
??? 最后,用Write_JPEG命令,將此幅24位的圖像用較好的圖像質量和適當的壓縮比輸出到JPEG文件。鍵入:
??? IDL> Write_JPEG, ‘test.jpg’, image3D, true=1, quality=75
??? 如果讀者有某個應用程序能打開和讀取JPEG文件的話,試著讀一下剛建立的文件。許多萬維網的瀏覽器都支持讀取JPEG文件??匆幌?#xff0c;如果瀏覽器有一個Open File按鈕,用它試試看能否讀取這個JPEG文件。
7.6 讀取JPEG文件
??? 用Read_JPEG命令就可以讀取并顯示一個JPEG文件。例如,如果打算在8位顯示器上顯示24位圖像,可以用下面這個命令:
?? ?IDL> Read_JPEG, ‘test,jpg’, thisImage, colortable,$
?? ?Colors=!D.Table_Size, Dither=1, /Two_Pass_Quantize
??? 關鍵字Colors指明24位圖像應該量化到多少種顏色,它的值應該是從8到256。關鍵字Dither 選擇Floyd-Steinbeig抖動法,它把顏色量化時的錯誤分散到旁邊的周圍的像素中去,從而獲得高質量的圖像。關鍵字Two_Pass_Quantize將顏色量化分為兩步進行處理,同樣也可以獲得更好的顏色量化效果和更高的圖像質量。
??? 顯示數據,鍵入:
??? IDL> Erase
??? IDL> Tv, thisImage
??? 所看到的可能有些奇怪。這是因為這幅圖像的顏色量化方法。為了看到輸出結果到底是什么,必須裝載與圖像相關的顏色表。這個顏色表返回在變量colortable中。裝載顏色表,鍵入:
??? IDL> TVLCT,colortable
?? ?假設正在8位顯示器上顯示24位的圖像,應該使用TV命令里的關鍵字True:
??? IDL> TV, thisimage, true=1
7.7 查詢圖像文件信息
??? 常用圖像文件格式的查詢程序已在IDL5.2版中提供。這些程序允許在沒有真正讀取其數據的情況下,就可以查詢圖像文件。這些程序可以存取隨著圖像數據文件一起存儲在文件里的元數據(關于數據的一些信息)。
下面是新的圖像查尋程序列表:
①?Query_BMP
②?Query_DICOM
③?Query_GIF
④?Query_JPEG
⑤?Query_PICT
⑥ Query_PNG
⑦ Query_PPM
⑧ Query_SRF
⑨?Query_TIFF
??? 所有這些查詢命令都是以同樣的方式工作。它們都是返回0或1的函數,通過返回值確定是否成功地(返回值為1)讀取了圖像文件里的元數據。如果它們成功地讀取了文件,將保存文件信息的IDL結構變量作為輸出命令返回給用戶。用戶通過存取這個結構里面的字段從而獲取文件的有關信息。
?? ?例如,查詢剛創建的JPEG文件,將文件的返回信息返回到變量fileinfo,可以鍵入:
?? ?IDL> k=Query_JPEG(‘test, jpg’, fileinfo)
??? 看看返回的是什么信息,鍵入:
??? IDL> Help, fileinfo, /Structure
??? 可以看到打印輸出的信息:
??? **Structure<1364998>, 7 tags, length=36, refs=1:
??? CHANNELS LONG 3
??? DIMENSIONS LONG Array[2]
??? HAS_PALETTE INT 0
??? IMAGE_INDEX LONG 0
??? NUM_IMAGES LONG 1
??? PIXEL_TYPE INT 1
??? TYPE STRING ‘JPEG’
??? 能夠看到此文件(Num_Image=1)里有一幅圖像,它是字節型數據(Pixel_Type=1),是一個24位的圖像(Channels=3)。這個圖像的大小能夠通過打印維數字段可以看到,如下:
??? IDL> Print, fileinfo.dimensions
??? 400 300
其它的圖像查詢程序在返回結構里含有類似的字段。
總結
以上是生活随笔為你收集整理的ENVI IDL读写数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 遥感RS植被指数大全整理
- 下一篇: C#生成二维码(含解码)