日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

图像处理(十)基于特征线的图像变形-Siggraph 1992

發布時間:2025/3/21 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图像处理(十)基于特征线的图像变形-Siggraph 1992 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這里要跟大家分享的paper為基于特征線的圖像 morphing,對應的英文文獻為《Feature-Based Image Metamorphosis》,是1992年SIGGRAPH?上的一篇paper,比較老的一篇paper,然而這篇paper引用率非常高,用于圖像變形效果還是挺不錯的,這個算法一般用于圖像的morphing。因為這篇paper算法原理簡單,易于實現,所以不用怕學習這個算法需要多長的時間。

開始之前先聲明一下,這篇博文主要參考自:http://www.csie.ntu.edu.tw/~b97074/vfx_html/hw1.html??同時結合我自己的理解,跟大家分享算法,幫助更多愛好者學習,非商業用途。

一、相關理論

我們知道圖像變形的本質,其實就是求取光流場,就是求取目標圖像的每一個像素點在原圖像的對應位置點,然后同過雙線性插值的方法就可以求得目標圖像。

1、單線段約束變形:


給定原圖像Source Image,我們希望把原圖像上的像素點P'、Q'位置移動到P、Q位置,那么其它的像素點的位置要怎么移動,才能使得得到的結果圖像Destination Image不會發生嚴重扭曲,這便是圖像變形的研究內容。如圖所示,如果用逆向映射的變形方法,對于目標圖像上的任意一點X,我們只需要求取source image 上的對應點X'就可以了,當然逆向映射X'往往不是整數,需要經過線性插值,獲取X'的像素值。

已知PQ,P'Q',X點,我們要怎么求出X的對應點X'呢?


其實很簡單,其原理是通過保證圖中二維(u,v)坐標不變就可以了,也就是我們可以通過上面的三個計算公式,求出X'。說的簡單一點呢,就是保證X相對于PQ的比例位置坐標(u,v)不變。

2、多線段約束變形

上面是對于單線段約束而言的,對于多線段的情況,主要是通過加權平均的方法。


如圖,現在已知P1Q1,P2Q2,X,以及源圖像的P1'Q1',P2'Q2',我們要求取X'點。

這個時候我們可以先用單線段約束的方法

(1)通過P1Q1 、P1'Q1'、X 計算出X1’;

(2)通過P2Q2 、P2'Q2'、X 計算出X2’;

然后通過加權平均的方法,求出X':


其中權值w的計算方法就是通過點X到線段的距離成反比的函數計算:


其中length表示線段的長度,dist表示點X到線段的最短距離。a,b,p為常數,對于它們的取值我們可以選p = 0 , a = 1 , b = 2。

ok,到了這里算法就結束了,感覺松松,我們就可以計算出X’點,


因為X'計算出來一般不可能剛好位于原圖像像素點的位置,因此我們需要通過雙線性插值的方法,求取X'的像素值。

看完上面應該知道怎么計算X'點了吧。接著我們要進入算法實現階段。

二、算法實現

說明以下代碼參考自:http://www.csie.ntu.edu.tw/~b97074/vfx_html/hw1.html

Algorithm:

1、根據公式1,2,計算X點相對于各線段的位置(u,v)坐標。


[cpp]?view plaincopy
  • double?new_u?=?dst_line.Getu(X);??
  • double?new_v?=?dst_line.Getv(X);??
  • [cpp]?view plaincopy
  • //公式1??
  • double?Line::Getu(Vector2?X)??
  • {??
  • ????double?X_P_x?=?X.x?-?P.x;???
  • ????double?X_P_y?=?X.y?-?P.y;??
  • ????double?Q_P_x?=?Q.x?-?P.x;??
  • ????double?Q_P_y?=?Q.y?-?P.y;??
  • ????double?u?=?((X_P_x?*?Q_P_x)?+?(X_P_y?*?Q_P_y))?/?(len?*?len)??;??
  • ????return?u?;??
  • }??
  • //公式2??
  • double?Line::Getv(Vector2?X){??
  • ????double?X_P_x?=?X.x?-?P.x;??
  • ????double?X_P_y?=?X.y?-?P.y;??
  • ????double?Q_P_x?=?Q.x?-?P.x;??
  • ????double?Q_P_y?=?Q.y?-?P.y;??
  • ????double?Perp_Q_P_x?=?Q_P_y?;????
  • ????double?Perp_Q_P_y?=?-Q_P_x?;??
  • ????double?v?=?((X_P_x?*?Perp_Q_P_x)?+?(X_P_y?*?Perp_Q_P_y))/len?;???
  • ????return?v?;???
  • }??
  • 2、根據公式3,然后反算X點在源圖像的位置對應點X'。

    [cpp]?view plaincopy
  • Vector2?src_point?=?src_line.Get_Point(new_u?,?new_v);??
  • [cpp]?view plaincopy
  • //根據u,v坐標可計算出pq線段的對應點x??
  • Vector2?Line::Get_Point(double?u?,?double?v)??
  • {??
  • ????double?Q_P_x?=?Q.x?-?P.x;??
  • ????double?Q_P_y?=?Q.y?-?P.y;??
  • ????double?Perp_Q_P_x?=?Q_P_y?;????
  • ????double?Perp_Q_P_y?=?-Q_P_x?;??
  • ????double?Point_x?=?P.x?+?u?*?(Q.x?-?P.x)?+?((v?*?Perp_Q_P_x)/len)?;??
  • ????double?Point_y?=?P.y?+?u?*?(Q.y?-?P.y)?+?((v?*?Perp_Q_P_y)/len)?;??
  • ????Vector2?X;??
  • ????X.x?=?Point_x;??
  • ????X.y?=?Point_y;??
  • ????return?X?;??
  • }??
  • 3、計算各個線段的權重。

    [cpp]?view plaincopy
  • double?src_weight?=?dst_line.Get_Weight(dst_point);??
  • [cpp]?view plaincopy
  • double?Line::Get_Weight(Vector2?X?)??
  • {??
  • ????double?a?=?parameter_a;??
  • ????double?b?=?parameter_b;??
  • ????double?p?=?parameter_p;??
  • ????double?d?=?0.0;??
  • ??
  • ????double?u?=?Getu(X);??
  • ????if(u?>?1.0?)??
  • ????????d?=?sqrt((X.x?-?Q.x)?*?(X.x?-?Q.x)?+?(X.y?-?Q.y)?*?(X.y?-?Q.y));??
  • ????else?if(u?<?0)??
  • ????????d?=?sqrt((X.x?-?P.x)?*?(X.x?-?P.x)?+?(X.y?-?P.y)?*?(X.y?-?P.y));??
  • ????else??
  • ????????d?=?abs(Getv(X));??
  • ??
  • ??
  • ????double?weight?=pow(pow((float)len,(float)p)/(a?+?d)?,?b);??
  • ????return?weight;???
  • }??
  • 然后對所有的X'點進行加權求和就可以了。

    ok,上面過程的代碼合在一起,遍歷每一條約束線段。

    4、最后進行雙線性插值。

    雙線性插值函數如下:

    [cpp]?view plaincopy
  • void?bilinear(BitmapData?*psrcImgData,float?X?,float?Y,byte*resultpiexl)??
  • {??
  • ????int?x_floor?=?(int)X?;??
  • ????int?y_floor?=?(int)Y?;??
  • ????int?x_ceil?=?x_floor?+?1?;??
  • ????int?y_ceil?=?y_floor?+?1?;??
  • ????float?a?=?X?-?x_floor?;??
  • ????float?b?=?Y?-?y_floor?;??
  • ??
  • ????if(x_ceil?>=?psrcImgData->Width-1)???
  • ????????x_ceil?=psrcImgData->Width-1?;??
  • ????if(y_ceil?>=?psrcImgData->Height-1)???
  • ????????y_ceil?=?psrcImgData->Height-1?;??
  • ????byte?leftdown[3];???
  • ????byte?lefttop[3];???
  • ????byte?rightdown[3];???
  • ????byte?righttop[3];???
  • ????Get2D(psrcImgData,y_floor,x_floor,leftdown);??
  • ????Get2D(psrcImgData,y_ceil,x_floor,lefttop);??
  • ????Get2D(psrcImgData,y_floor,x_ceil,rightdown);??
  • ????Get2D(psrcImgData,y_ceil,x_ceil,righttop);??
  • ????for(int?i?=?0?;?i?<?3?;?i?++)??
  • ????{??
  • ????????resultpiexl[i]?=?(1-a)*(1-b)*leftdown[i]?+?a*(1-b)*rightdown[i]?+?a*b*righttop[i]?+?(1-a)*b*lefttop[i];??
  • ????}??
  • }??
  • void?Get2D(BitmapData?*psrcImgData,?int?Y,int?X,?byte*piexl)??
  • {??
  • ????byte*pdata=(byte*)psrcImgData->Scan0+(psrcImgData->Width*Y+X)*4;??
  • ????for?(int?i=0;i<3;i++)??
  • ????{??
  • ????????piexl[i]=pdata[i];??
  • ????}??
  • ??
  • }??

  • 最后貼一下整個過程的代碼:

    [cpp]?view plaincopy
  • int?nWidth=prightImgData->Width;??
  • int?nHeight=prightImgData->Height;??
  • ???for(int?x?=?0?;?x?<?nWidth?;?x++)??
  • {??
  • ???????for(int?y?=?0?;?y?<?nHeight?;?y++)??
  • ????{??
  • ????????Vector2?dst_point?;??
  • ????????dst_point.x=?x?;???
  • ????????dst_point.y=?y;??
  • ????????double?leftXSum_x?=?0.0;??
  • ????????double?leftXSum_y?=?0.0;??
  • ????????double?leftWeightSum?=?0.0;??
  • ????????double?rightXSum_x?=?0.0;??
  • ????????double?rightXSum_y?=?0.0;??
  • ????????double?rightWeightSum?=?0.0;??
  • ????????for(int?i?=?0?;?i?<?pairs.size()?;?i++)??
  • ????????{??
  • ??
  • ????????????Line?src_line?=?pairs[i].leftLine;????
  • ????????????Line?dst_line?=?pairs[i].rightLine;??
  • ??
  • ????????????double?new_u?=?dst_line.Getu(X);//計算(u,v)坐標??
  • ????????????double?new_v?=?dst_line.Getv(X);??
  • ??
  • ????????????Vector2?src_point?=?src_line.Get_Point(new_u?,?new_v);//計算源圖像的對應點X'??
  • ????????????double?src_weight?=?dst_line.Get_Weight(dst_point);//計算權重??
  • ????????????leftXSum_x?=?leftXSum_x?+?(double)src_point.x?*?src_weight?;//加權求X'的平均位置??
  • ????????????leftXSum_y?=?leftXSum_y?+?(double)src_point.y?*?src_weight?;??
  • ????????????leftWeightSum?=?leftWeightSum?+?src_weight?;??
  • ????????}??
  • ????????double?left_src_x?=?leftXSum_x?/?leftWeightSum;??
  • ????????double?left_src_y?=?leftXSum_y?/?leftWeightSum;??
  • ????????double?right_src_x?=?x;??
  • ????????double?right_src_y?=?y;??
  • ??
  • ??
  • ????????if(left_src_x<0)//判斷是否越界??
  • ????????????left_src_x=0;??
  • ????????if(left_src_y<0)??
  • ????????????left_src_y=0;??
  • ????????if(left_src_x>=pleftImgData->Width)??
  • ????????????left_src_x=pleftImgData->Width-1;??
  • ????????if(left_src_y>=pleftImgData->Height)??
  • ????????????left_src_y=pleftImgData->Height-1;??
  • ??
  • ????????byte?leftimg[3];//存儲最后的(x,y)點的像素值??
  • ????????bilinear(pleftImgData,left_src_x,left_src_y,leftimg);//線性插值??
  • ????????for?(int?i=0;i<3;i++)??
  • ????????{??
  • ????????????float?newpiexl=leftimg[i];??
  • ??
  • ??
  • ????????}??
  • ???????}??
  • ???}??
  • 本文地址:http://blog.csdn.net/hjimce/article/details/45531039?? ? 作者:hjimce ? ? 聯系qq:1393852684 ??更多資源請關注我的博客:http://blog.csdn.net/hjimce? ? ? ? ? ? ? ? 原創文章,轉載請保留本行信息。

    最后看一下,用這個算法實現的變形融合:

    原圖像:


    變形融合結果:


    參考文獻:

    1、http://www.csie.ntu.edu.tw/~b97074/vfx_html/hw1.html
    2、Feature-Based Image Metamorphosis

    總結

    以上是生活随笔為你收集整理的图像处理(十)基于特征线的图像变形-Siggraph 1992的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。