影象濾鏡--圖象扭曲演算法

查志強發表於2014-11-25

【原文:http://blog.csdn.net/pizi0475/article/details/12770813

圖象扭曲是平面圖形變化的一種,它可用於許多場合,如在以前介紹的火焰特效中加入扭曲效果,會使火焰更逼真(當然程式碼要有更高的的效率才行),如果在字幕當中加入扭曲效果,會給人一種怪異的感覺。

  圖象扭曲的演算法並不複雜,但要解釋清楚卻不是一件容易的事,為了說明問題只好借用圖片了,網路慢的朋友多多包涵了。演算法例程原始碼編譯需VC++、DXSDK、DXGuide。



圖一 圖二 圖三

  首先我們來看圖一,大家可看出在圖中有一些網格線,這裡假定這些網格線是一些有彈性

的細繩,在圖一中假定網格線是與底層分離的,接下來我們要在網格線的結點處施加外力,網格線受外力後就會變成象圖二的形狀,大家要仔細看圖一和圖二的底圖,變化的僅僅是網格線,而底圖目前為止還沒改變。

  再下來就是關鍵的地方了,到目前為止,我們還是假定網格線是與底圖分離開的,接下來我們要把圖二中網格線附著在底圖上,然後撤消外力,記住網格線是有彈性的,這時底圖在網格線的帶動下發生變形,直到網格線回覆到原樣,如圖三。大家再仔細看看圖三的底圖,是不是已被扭曲?

是不是恍然大悟?接下來就好解釋了,我們再來看看圖二到圖三中某個固定的網格是如何形變的,


圖四

圖二中的網格是不規則形狀的四邊形,圖三中的則是正方形。網格的形變其實就是四邊形的擠壓和拉伸的過程,如圖四,藍色是變形前的圖象,綠色就是變形後的圖象,則演算法只是簡單的縮放運算而已。假定正方形是16*16點的圖塊,將正方形各點投射到不規則四邊形上,則在正方形上各點的顏色值就取不規則四邊形上相應的投影點處的顏色值就行了。具體演算法見原始碼。

  1. // 單元塊扭曲演算法   
  2. inline void CFeedBackApp::TextureBlock(int xo, int yo)  
  3. {  
  4.     // 投影平面   
  5.     float fLeftOffX, fLeftOffY;     // 各行左端點相對於上一行左端點的偏移   
  6.     float fRightOffY, fRightOffX;   // 各行右端點相對於上一行右端點的偏移   
  7.     float TX1, TY1, TX2, TY2;       // 當前行左、右端點的座標   
  8.     float HDx, Hdy;                 // 當前行各點間的平均偏移量   
  9.     float tx, ty;                   // 當前投影點座標   
  10.     // 渲染平面   
  11.     int x, y;                       // 當前渲染點座標   
  12.     int xi=(xo<<4), yi=(yo<<4);     // 當前渲染塊左上角座標   
  13.     WORD *Tptr;  
  14.     Tptr = &(m_awBuf1[xi + m_nMul640[yi]]);  
  15.     fLeftOffX = (m_offset[xo]  [yo+1].xint - m_offset[xo]  [yo].xint) /16; // 計算平均偏移   
  16.     fLeftOffY = (m_offset[xo]  [yo+1].yint - m_offset[xo]  [yo].yint) /16;  
  17.     fRightOffX = (m_offset[xo+1][yo+1].xint - m_offset[xo+1][yo].xint) /16;  
  18.     fRightOffY = (m_offset[xo+1][yo+1].yint - m_offset[xo+1][yo].yint) /16; // 計算平均偏移   
  19.     TX1  = m_offset[xo]  [yo].xint;     // 取投影圖塊第一行左端點座標   
  20.     TY1  = m_offset[xo]  [yo].yint;  
  21.     TX2  = m_offset[xo+1][yo].xint;     // 取投影圖塊第一行右端點座標   
  22.     TY2  = m_offset[xo+1][yo].yint;  
  23.     for (y=yi; y < (yi+16); y++)  
  24.     {  
  25.         HDx  = (TX2-TX1) / 16;          // 計算投影圖塊當前行各點的平均偏移   
  26.         Hdy  = ((TY2-TY1) / 16);  
  27.         tx = TX1;                       // 投影平面當前行左端點座標   
  28.         ty = TY1;  
  29.         for (x=xi; x < (xi+16); x++)  
  30.         {  
  31.             *Tptr++ = m_awBuf2[int(tx) + m_nMul640[int(ty)] ];  
  32.             tx += HDx;                  // 下一點   
  33.             ty += Hdy;  
  34.         }  
  35.         Tptr += (SCRWIDTH-16);          // 下一行   
  36.         TX1 += fLeftOffX;               // 計算投影平面中下一行左、右端點的座標   
  37.         TY1 += fLeftOffY;  
  38.         TX2 += fRightOffX;  
  39.         TY2 += fRightOffY;  
  40.     }  
  41. }  
  1. // 單元塊扭曲演算法  
  2. inline void CFeedBackApp::TextureBlock(int xo, int yo)  
  3. {  
  4.     // 投影平面  
  5.     float fLeftOffX, fLeftOffY;     // 各行左端點相對於上一行左端點的偏移  
  6.     float fRightOffY, fRightOffX;   // 各行右端點相對於上一行右端點的偏移  
  7.     float TX1, TY1, TX2, TY2;       // 當前行左、右端點的座標  
  8.     float HDx, Hdy;                 // 當前行各點間的平均偏移量  
  9.     float tx, ty;                   // 當前投影點座標  
  10.     // 渲染平面  
  11.     int x, y;                       // 當前渲染點座標  
  12.     int xi=(xo<<4), yi=(yo<<4);     // 當前渲染塊左上角座標  
  13.     WORD *Tptr;  
  14.     Tptr = &(m_awBuf1[xi + m_nMul640[yi]]);  
  15.     fLeftOffX = (m_offset[xo]  [yo+1].xint - m_offset[xo]  [yo].xint) /16; // 計算平均偏移  
  16.     fLeftOffY = (m_offset[xo]  [yo+1].yint - m_offset[xo]  [yo].yint) /16;  
  17.     fRightOffX = (m_offset[xo+1][yo+1].xint - m_offset[xo+1][yo].xint) /16;  
  18.     fRightOffY = (m_offset[xo+1][yo+1].yint - m_offset[xo+1][yo].yint) /16; // 計算平均偏移  
  19.     TX1  = m_offset[xo]  [yo].xint;     // 取投影圖塊第一行左端點座標  
  20.     TY1  = m_offset[xo]  [yo].yint;  
  21.     TX2  = m_offset[xo+1][yo].xint;     // 取投影圖塊第一行右端點座標  
  22.     TY2  = m_offset[xo+1][yo].yint;  
  23.     for (y=yi; y < (yi+16); y++)  
  24.     {  
  25.         HDx  = (TX2-TX1) / 16;          // 計算投影圖塊當前行各點的平均偏移  
  26.         Hdy  = ((TY2-TY1) / 16);  
  27.         tx = TX1;                       // 投影平面當前行左端點座標  
  28.         ty = TY1;  
  29.         for (x=xi; x < (xi+16); x++)  
  30.         {  
  31.             *Tptr++ = m_awBuf2[int(tx) + m_nMul640[int(ty)] ];  
  32.             tx += HDx;                  // 下一點  
  33.             ty += Hdy;  
  34.         }  
  35.         Tptr += (SCRWIDTH-16);          // 下一行  
  36.         TX1 += fLeftOffX;               // 計算投影平面中下一行左、右端點的座標  
  37.         TY1 += fLeftOffY;  
  38.         TX2 += fRightOffX;  
  39.         TY2 += fRightOffY;  
  40.     }  
  41. }  


相關文章