2013年9月9日 星期一

Matlab入門課程(3)字串處理

之前在FORTRAN入門課程裡面談到字串處理功能最容易被人忽視,Matlab何嘗不是呢?大家都以為Matlab最詭異的功能,也最容易被「經常作矩陣運算的人」所忘記的功能就是字串處理功能,這種經常在其他語言中看到的功能,卻很少被寫FORTRAN或者Matlab的人重視。
因為,寫FORTRAN/Matlab的人不會想到從一堆雜亂的資料中,挖出自己想要的內容, 可能情願自己打一個簡單清楚的資料檔,或者用記事本、Execl先把資料處理處理,在拿給Fortran/Matlab程式讀取使用。
 例如,有一個ENVI軟體產生的header,其內容如下

ENVI
description = {
  Create New File Result [Fri Jul 22 14:32:54 2005]}
samples = 5760
lines   = 9092
bands   = 4
header offset = 0
file type = ENVI Standard
data type = 2
interleave = bsq
sensor type = Unknown
byte order = 0
map info = {UTM, 1.000, 1.000, 231562.584, 2598337.772, 
1.0000000000e+000, 1.0000000000e+000, 51, North, WGS-84, units=Meters}
wavelength units = Unknown
pixel size = {1.00000000e+000, 1.00000000e+000, units=Meters}

上面這個檔案是由ENVI自動產生,其中samples=5760表示影像矩陣的nx大小,
lines=9092表示影像矩陣的ny大小,我們該如何讀出這二個值呢?

function envi_header
 fid=open('envi_image.hdr','r')
  % 跳過3列資料
  tline=fgetl(fid);
  tline=fgetl(fid);
  tline=fgetl(fid);
  % 將資料讀入 aLine 字串變數.
  tline=fgetl(fid);
  % 算出等號之後一位的位置
   n=strfind(tline,'=')+1;
  % 從等號之後一位的位置到第最後一個字元讀入nx
  nx=sscanf(tline(n:end),'%d');

  tline=fgetl(fid);
  % 算出等號之後一位的位置
   n=strfind(tline,'=')+1;
  % 從等號之後一位的位置到第最後一個字元讀入nx
  ny=sscanf(tline(n:end),'%d');
fclose(fid); disp(['nx,ny=' num2str(nx) ', ' num2str(ny)]) % 動態配置矩陣. red=uint8(zeros(nx,ny));
        green=uint8(zeros(nx,ny));
        blue=uint8(zeros(nx,ny));

......


2013年9月8日 星期日

Matlab入門課程(1)解決最簡單的問題

前幾天,碰到一位同學來詢問我有關簡單的資料處理問題,討論完演算法之後,問他打算用什麼語言來寫,他很靦腆的說C++。我說用Matlab就可以了,不必用到C++吧?

大家或許覺得Matlab只適合在校園使用,所以,在學生時代就會勉勵自己要用未來可以找到工作的程式語言來寫,有關這一點,我並不反對。

但是,如果一個簡單的問題,要花掉好多時間去處理,連畢業都有困難,還擔心畢業以後的事情嗎?我建議先把資料處理的基本功夫學好,再談用C++開發大型的系統。

這一篇文章是延續 FORTRAN入門課程(1)解決最簡單的問題 同樣的內容,只是用Matlab來寫

fid1=fopen('data.xyz','r');
fid2=fopen('new_data.xyz','w');
        while 1
            tline = fgetl(fid1);
            if ~ischar(tline), break, end
            A=sscanf(tline,'%f, %f,%f');
            x=A(1); y=A(2); z=A(3);
            fprintf(fid2,'%f,%f,%f\r\n',x,y,-z);
        end
fclose(fid1);
fclose(fid2);

這個程式使用下列幾個Matlab基本的觀念

  • 檔案開啟(fopen)與關閉(fclose)
  • 檔案讀取(fgetl)與寫入(fprintf)
  • 字串處理(sscanf)
  • 迴圈(while loop)
  • 決策(if)
這個程式的基本精神是用fgetl函數將整列資料當成字串,讀入tline字串變數中
再用sscanf函數,將x,y,z三個變數讀入A矩陣中,在輸出的時候,才改變z的符號


2005年11月2日 星期三

FORTRAN入門課程(3)字串處理

FORTRAN最詭異的功能,也最容易被「經常作數值運算的人」所忘記的功能就是字串處理功能,這種經常在其他語言中看到的功能,卻很少被寫FORTRAN的人重視。
因為,寫FORTRAN的人不會想到從一堆雜亂的資料中,挖出自己想要的內容, 可能情願自己打一個簡單清楚的資料檔, 例如,有一個ENVI軟體產生的header,其內容如下

ENVI
description = {
  Create New File Result [Fri Jul 22 14:32:54 2005]}
samples = 5760
lines   = 9092
bands   = 4
header offset = 0
file type = ENVI Standard
data type = 2
interleave = bsq
sensor type = Unknown
byte order = 0
map info = {UTM, 1.000, 1.000, 231562.584, 2598337.772, 
1.0000000000e+000, 1.0000000000e+000, 51, North, WGS-84, units=Meters}
wavelength units = Unknown
pixel size = {1.00000000e+000, 1.00000000e+000, units=Meters}

上面這個檔案是由ENVI自動產生,其中samples=5760表示影像矩陣的nx大小,
lines=9092表示影像矩陣的ny大小,我們該如何讀出這二個值呢?


program envi_header
 integer(kind=2),allocatable :: red(:,:),green(:,:),blue(:,:)
 character(len=80)  :: aLine

 open(10,file='envi_image.hdr',status='old')
  ! 跳過3列資料
  read(10,*)
  read(10,*)
  read(10,*)
  ! 將資料讀入 aLine 字串變數.
  read(10,'(a)')aLine
  ! 算出等號之後一位的位置
  n=index(aLine,'=')+1
  ! 從等號之後一位的位置到第80個字讀入nx
  read(aLine(n:80),*)nx

  read(10,'(a)')aLine
  n=index(aLine,'=')+1
  read(aLine(n:80),*)ny
 close(10)
 write(*,*)'nx,ny=',nx,ny

 ! 動態配置矩陣.
 allocate(red(nx,ny),green(nx,ny),blue(nx,ny))
......

stop
end

FORTRAN入門課程(2)如果檔案太大打不開?


大家還記得在VB/VB .NET有下列的故事...

一位學弟問了一個大家經常碰到的問題,如果檔案太大打不開,怎麼辦?
有人說用UltraEdit應該沒有打不開的檔案。

那麼用FORTRAN怎麼寫呢?

program head
character(len=100) :: in_file,aLine
integer(kind=2)    :: NL,i

write(*,*)'file name?'
read(*,'(a)')in_file

write(*,*)'how many lines?'
read(*,*)NL

open(10,file=in_file,status='old')
do i=1,NL
   read(10,'(a)')aLine
   write(*,'(a)')aLine
end do
close(10)
stop
end

2005年8月17日 星期三

如果檔案太大打不開?

寫在前面:
這是筆者比較早期的文章,同樣的主題,如果以程式導向設計觀念去做,不會寫成這樣。


一位學弟問了一個大家經常碰到的問題,如果檔案太大打不開,怎麼辦?
有人說用UltraEdit應該沒有打不開的檔案。

那您可能沒有碰過一個659MB的文字檔吧?有位學弟每次用UltraEdit打開這個檔案,
出去吃過午餐之後UltraEdit才打開...

這個問題和之前在FORTRAN的課程裡「 FORTRAN入門課程(1)解決最簡單的問題」,
有異曲同工之妙。

這位學弟比較擅長VB,好吧,先用VB6畫一個類似下列的畫面


然後,分別把下列兩組code打進「開啟」和「讀取」兩個按鈕中。
「開啟」按鈕程式碼
Private Sub cmdOpen_Click()  
    CommonDialog1.ShowOpen
    '如果使用者沒選檔案時CommonDialog1.FileName是空字串
    If (Len(CommonDialog1.FileName) > 0) Then
        txtInputFile.Text = CommonDialog1.FileName
    End If
End Sub
「讀取」按鈕程式碼
Private Sub cmdRead_Click()
    Dim aLine As String
    Dim i As Integer
    dim FID as Integer

    List1.Clear
    '讓系統自動抓出可用的檔案號碼
    FID=FreeFile
    Open txtInputFile.Text For Input As #FID
    
        For i = 1 To Val(txtNumLines.Text)
            Line Input #FID, aLine
            List1.AddItem aLine
        Next i
        
    Close #FID
End Sub

以下是這個程式的執行畫面


按下「開啟」按鈕會出現下列畫面
 
選完您要預覽的檔案,按下「讀取」按鈕後,就可以看到龐大檔案的前20列!
如此一來,就不必出去吃過午餐之後UltraEdit才打開..., 注意看,這個檔案有47,655KB(約60萬筆資料)!! 至於,檔案內容是什麼,應該不必秀了吧?

如果,還想多看一點內容,可以把20改成您所想要的數字即可。
千萬要注意,VB的ListBox超過一定數量之後,就很...很...很........慢 :< 
如果, 你想讓您的生活變成彩色...
捲起袖子, 現在就開始吧.

2005年8月2日 星期二

以平常心步向成功

看到有許多年輕的朋友,常覺得自己在人生的路上,如此努力的奮鬥, 得到的卻只有徬徨、無力的感覺。我愛把這篇自己年輕的時候,看到的勵志小品與他們分享...

以平常心步向成功
1.給自己足夠的時間學習技能,打好基礎--成功之路捨努力別無捷徑。
2.要實際
達到目標需要時間,人不可能一夕之間成功,不要不耐煩。
3.不要太早放棄
哀莫大於心死,一旦放棄,你就永遠無法知道你是否有能力達成目標。
4.時時往積極的一面想
不要太在意失敗。一旦你開始覺得自己沒有能力作,你就不會再嘗試。
5.要有自己的標準
不要用別人的標準來衡量自己。
6.最重要的是,不管發生什麼事,都要認為自己還不錯。
78.12.20

多讀聖經
93.3.1

最近忙一個案子,連續好幾個星期精神緊張,這個星期更是每天挑燈夜戰,拼了老命想如期完成,連教會都不去,更別提讀經禱告。昨天,在一陣忙碌卻得不到結果的時候,突然覺得人為什麼總愛和自己過不去?

原因到底出在那裡?這時候才發覺已經好幾天沒看email,好幾天沒陪家人...
看到自己寫的這篇「以平常心步向成功」,不禁莞爾,什麼是平常心?看到這篇文章雖然已經快15年了,可是卻從來不是以平常心去完成事情。

每次都是在事後才拿出來,彷彿自己是以一種平常心,一步一步完成許多事情。

回想自己總喜歡把自己逼的太緊,喜歡把時間表塞的滿滿的。人往往會高估自己的實力,也低估了完成每一件事情所需要的時間。

事到臨頭了,就會驚惶失措。

94.8.2

2005年7月22日 星期五

FORTRAN入門課程(1)解決最簡單的問題

很多人很怕學FORTRAN,記得大三的時候(1986年),航空系的同學跑來問我有關FORTRAN的問題,
陪他一起來的同學很感嘆,學習「福傳」會讓別人恥笑,還是學習像c語言這樣的東西吧!

如果,您同意他的看法,也沒錯,因為,FORTRAN不但是古老而且是很保守的語言。
但是,一但被FORTRAN拿來用的功能,就會千古流傳。

接下來,開始介紹今天的課程動機:
有一天,另外一個部門的人跑來請我幫忙,有一批資料雖然只有三個欄位x,y,z
因為資料太大,不管用什麼軟體都打不開這個資料檔。

問我有什麼方法可以很快的把正負號顛倒(資料有正有負)?
當時正好要去開會,就請一位新進的同仁小陳幫忙處理。

才剛開完會回來,小陳告訴我資料已經處理好了,我很驚訝他怎麼這麼厲害?
以下是他寫的FORTRAN程式:

program change_sign
   real(kind=8) :: x,y,z
   open(10,file='data.xyz',status='old')
   open(20,file='new_data.xyz',status='unknown')
   do while (.not.eof(10))
 read(10,*)x,y,z
 write(20,*)x,y,-z
   end do
   close(10)
   close(20)
stop
end

我一看,好漂亮(本來想說好簡短)的FORTRAN程式!!!
大家不要看這個程式很短喲,當天拿來的資料檔共有4000萬筆! 如果用Execl開啟,只能處理前65536筆資料呢。
為了教學方便,我把這個程式註解了一下:

program change_sign
   ! 宣告x,y,z變數
   real(kind=8) :: x,y,z

   ! 開啟原資料檔
   open(10,file='data.xyz',status='old')

   ! 開啟輸出資料檔
   open(20,file='new_data.xyz',status='unknown')

   ! 處理10號檔案裡面所有的資料,直到eof(end of file)
   do while (.not.eof(10))
 read(10,*)x,y,z
 write(20,*)x,y,-z
   end do

   ! 關閉資料檔
   close(10)
   close(20)
stop
end

這個程式的作業流程,請參考 如何用程式解決問題-2