程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB綜合教程 >> VB圖像處理之二次線性插值的應用

VB圖像處理之二次線性插值的應用

編輯:VB綜合教程
上次講到了用DIB方法來獲取圖像的像素。從這次開始將如果運用已經得到的像素來處理圖像。
  
  圖像插值放大的方法有很多,最主要的有二次線性插值和三次線性插值這兩種。這次我把自己的程序中所用的二次線性插值的算法公布給大家,希望對各位要使用VB寫類似程序的朋友有所幫助。
  
  程序中用到的API、數據類型、全局變量的定義請參考上一篇:《VB實現圖像在數據庫的存儲與顯示》
  
  ->PublicSubZoomImage(ByValOutPutWidthAsLong,ByValOutputHeightAsLong)
   DimIAsLong
   DimLAsLong
   DimXAsLong
   DimYAsLong
   DimXbAsLong
   DimYbAsLong
   DimXeAsLong
   DimYeAsLong
   DimMAsInteger
   DimNAsInteger
   DimCurRAsLong
   DimCurGAsLong
   DimCurBAsLong
   DimNxtRAsInteger
   DimNxtGAsInteger
   DimNxtBAsInteger
   DimDRAsSingle
   DimDGAsSingle
   DimDBAsSingle
   DimDRtAsSingle
   DimDGtAsSingle
   DimDBtAsSingle
   DimXratioAsSingle
   DimYratioAsSingle
   DimCurStepAsSingle
   DimNxtStepAsSingle
   DimNegNAsSingle
  
   OnErrorGoToErrLine
   IfNotCanZoomThenExitSub
   Done=False
  
   OutPutWid=OutPutWidth-1
   OutPutHei=OutputHeight-1
   I=(Bits8)-1
   ReDimColTmp(I,InPutWid,OutPutHei)'先從Y方向進行縮放處理,結果保存在此中間數組內
   ReDimColOut(I,OutPutWid,OutPutHei)
   Xratio=OutPutWid/InPutWid
   Yratio=OutPutHei/InPutHei
  
   TimeZoom=timeGetTime
  
   NegN=1/Int(Yratio 1)
   ForX=0ToInPutWid
  CurR=ColVal(0,X,0)
  CurG=ColVal(1,X,0)
  CurB=ColVal(2,X,0)
  CurStep=0
  NxtStep=0
  ForY=0ToInPutHei-1
   NxtStep=CurStep Yratio
   Yb=CurStep
   Ye=NxtStep
   N=Ye-Yb
   ColTmp(0,X,Yb)=CurR
   ColTmp(1,X,Yb)=CurG
   ColTmp(2,X,Yb)=CurB
   M=Y 1
   NxtR=ColVal(0,X,M)
   NxtG=ColVal(1,X,M)
   NxtB=ColVal(2,X,M)
   IfN>1Then
  DRt=(NxtR-CurR)*NegN
  DGt=(NxtG-CurG)*NegN
  DBt=(NxtB-CurB)*NegN
  DR=0
  DG=0
  DB=0
  ForL=Yb 1ToYe-1
   DR=DR DRt
   DG=DG DGt
   DB=DB DBt
   ColTmp(0,X,L)=CurR DR
   ColTmp(1,X,L)=CurG DG
   ColTmp(2,X,L)=CurB DB
  Next
   EndIf
   CurStep=NxtStep
   CurR=NxtR
   CurG=NxtG
   CurB=NxtB
  Next
  ColTmp(0,X,OutPutHei)=NxtR
  ColTmp(1,X,OutPutHei)=NxtG
  ColTmp(2,X,OutPutHei)=NxtB
   Next
  
   NegN=1/Int(Xratio 1)
   ForY=0ToOutPutHei
  CurR=ColTmp(0,0,Y)
  CurG=ColTmp(1,0,Y)
  CurB=ColTmp(2,0,Y)
  CurStep=0
  NxtStep=0
  ForX=0ToInPutWid-1
   NxtStep=CurStep Xratio
   Xb=CurStep
   Xe=NxtStep
   N=Xe-Xb
   ColOut(0,Xb,Y)=CurR
   ColOut(1,Xb,Y)=CurG
   ColOut(2,Xb,Y)=CurB
   M=X 1
   NxtR=ColTmp(0,M,Y)
   NxtG=ColTmp(1,M,Y)
   NxtB=ColTmp(2,M,Y)
   IfN>1Then
  DRt=(NxtR-CurR)*NegN
  DGt=(NxtG-CurG)*NegN
  DBt=(NxtB-CurB)*NegN
  DR=0
  DG=0
  DB=0
  ForL=Xb 1ToXe-1
   DR=DR DRt
   DG=DG DGt
   DB=DB DBt
   ColOut(0,L,Y)=CurR DR
   ColOut(1,L,Y)=CurG DG
   ColOut(2,L,Y)=CurB DB
  Next
   EndIf
   CurStep=NxtStep
   CurR=NxtR
   CurG=NxtG
   CurB=NxtB
  Next
  ColOut(0,OutPutWid,Y)=NxtR
  ColOut(1,OutPutWid,Y)=NxtG
  ColOut(2,OutPutWid,Y)=NxtB
   Next
  
   Done=True
   TimeZoom=timeGetTime-TimeZoom
   CanPut=True
   ExitSub
  ErrLine:
   MsgBoxErr.Description
  EndSub->
  全局變量定義:
  
  ->DimColTmp()AsByte'用於保存插值中間變量
  DimOutPutHeiAsLong'要插值的目標高度
  DimOutPutWidAsLong'要插值的目標寬度
  PublicTimeZoomAsLong'插值運算使用的時間->
  簡單解釋一下關於二次線性插值算法。
  
  (為了說明算法本身,我們只計算這個圖片的紅色分量,因為紅綠藍三種顏色的計算方法完全相同)
  
  假設我們有一個很簡單的圖片,圖片只有4個像素(2*2)
  
  ->AB
  CD->
  現在我們要把這個圖片插值到9個像素:3*3
  
  ->AabB
  acabcdbd
  CcdD->
  其中大寫的字母代表原來的像素,小寫字母代表插值得到的新像素。
  
  想必看到這個圖,大家心裡已經有了這個算法了。
  
  ->ab=(A B)/2
  cd=(C D)/2
  ac=(A C)/2
  bd=(B D)/2
  abcd=(ab cd)/2=(A B C D)/4->
  推導:
  
  ->ab=A (B-A)/2
  cd=C (D-C)/2
  ...->
  很簡單,對吧,先從一個方向把只涉及兩個原始像素的新像素算出來。我們這裡假定先計算水平方向。而在算垂直方向的插值的時候,因為ab和cd已經在前面算好了,所以abcd的計算也和計算ac和bd沒有任何區別了。
  
  有可能為有朋友已經想到把原來的圖像插值到4*4或5*5的方法了。
  
  ->Aab1ab2B
  ac1ab1cd11ab2cd21bd1
  ac2ab1cd12ab2cd22bd2
  Ccd1cd2D->
  推導:
  
  ->ab1=A (B-A)*1/3
  ab2=A (B-A)*2/3=ab1 (B-A)/3
  cd1=C (D-C)*1/3
  cd1=C (D-C)*2/3=cd1 (D-C)/3
  ...->
  以A和B為例,先求出原始像素的差(A-B)再算出每一步的遞增量(A-B)/3;然後每一個新的點就是在前面那個點的值加上這個遞增量就是了。
  
  這裡我們假設A=100,B=255放大倍率為3,水平方向插值;先計算出原始像素的差:(B-A)=255-100=155
  
  再計算出水平方向每一步的遞增量:(A-B)/3=155/3=51.7
  
  這裡我們用一個變量DRt來記錄這個遞增量(這裡只用紅色來做例子)
  
  ->ab1=A DRt=100 51.7=151
  ab2=ab1 DRt=151 51.7=202->
  好了,其實二次線性算法就是這麼一個東西,並不復雜。或許有寫朋友會對於我給出的代碼產生疑問。很簡單的一個算法為什麼要寫這麼多代碼。
  
  其實答案很簡單:為了提高速度。
  
  在VB中“ ”和“-”永遠是最快的,“*”要比“/”和“”快。不論是什麼類型的變量都是這樣的。
  
  下面再來分析一下我的程序。
  
  在我的程序中把兩個方向的插值分解成了兩個單獨的部分。
  
  先把
  
  ->AB
  CD->
  變成:
  
  ->Aab1...abNB
  Ccd1...cdND->
  再變成:
  
  ->Aab1...abNB
  ac1.............db1
  ..................
  acN..............bdN
  Ccd1...cdND->
  這兩個方向的插值算法完全相同
  
  而Xratio和Yratio這兩個變量則用來記錄水平方向和垂直方向的放大倍率。所以這個過程也能夠讓圖像縮放不按照原始的縱橫比進行。
  
  好了,將這個模塊和全局變量添加到上次建立的工程模塊中。
  
  把按鈕中的代碼改成:
  
  ->subcommand1_click()
   Withpicture1
  .ScaleMode=3
  .BorderStyle=0
  DibGet.hdc,0,0,.scalewidth,.scaleheight
  ZoomImage,.scalewidth*2,.scaleheight*2
   EndWith
   picture2.AutoRedraw=True
   DibPutpicture2.hdc
   picture2.refresh
  endsub->
  圖像是否已經放大到原來的兩倍了呢?速度不算很慢吧?
  
  什麼?很慢?先編譯成EXE再運行吧。下面是效果圖:
  
  原圖:
  
  ->->
  二次線性插值放大5倍:
  
  ->->
  關於二次線性插值就說到這裡了->

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