變換使用的模板必須是單連通的,而且模板中心必須在模板內,如果在模板中打個結或是月牙形,這裡的程式就處理不了了。
雖然非單連通模板也有辦法處理,不過不是這裡要討論的。
這裡用到的方法和矩形變換為圓那片文章中用的方法幾乎一樣,變換前後畫素按比例縮減,不過在判斷弧度和影象邊界到模板中心距離時略有不同。
變換為圓時弧度可以直接計算出來,而變換為任意形狀只能算出一個最小相似值。
至於影象邊界到模板中心距離只能分八種情況判斷了,處理圓時可以根據對稱性簡化程式,這裡似乎沒有什麼好辦法簡化。
變換細節上,那篇文章中使用的是正向插值,這裡使用正向插值則會產生很多空洞,因此選擇了更常見的逆向插值。
處理結果如下:
原圖:
模板:
結果:
matlab程式碼如下:
clear all;close all;clc; img=imread('lena.jpg'); mask_line=imread('mask.bmp')>50; [h w]=size(img); imgn=zeros(h,w); ind=find(mask_line==1); [lineY lineX]=ind2sub([h w],ind); %模板形狀畫素的位置 cenY=round(mean(lineY)); %模板形狀中心 cenX=round(mean(lineX)); lineAng=atan2(lineY-cenY,lineX-cenX); %模板線上每個點到形狀中心弧度 lineR=sqrt((lineY-cenY).^2+(lineX-cenX).^2); %模板線上每個點到形狀中心距離 ang_ul=atan2(1-cenY,1-cenX); %影象四個點與模板形狀中心弧度 ang_ur=atan2(1-cenY,w-cenX); ang_dl=atan2(h-cenY,1-cenX); ang_dr=atan2(h-cenY,w-cenX); for y=1:h for x=1:w r=sqrt((x-cenX)^2+(y-cenY)^2); ang=atan2(y-cenY,x-cenX); if ang>=-pi && ang<ang_ul %分別求八個象限影象邊界到模板中心距離 R=abs(cenX/cos(ang)); %應該可以簡化,這樣判斷似乎繁瑣了 elseif ang>=ang_ul && ang<-pi/2 R=abs(cenY/cos(pi/2-ang)); elseif ang>=-pi/2 && ang<ang_ur R=abs(cenY/cos(pi/2+ang)); elseif ang>=ang_ur && ang<0 R=abs((w-cenX)/cos(pi-ang)); elseif ang>=0 && ang<ang_dr R=abs((w-cenX)/cos(ang)); elseif ang>=ang_dr && ang< pi/2 R=abs((h-cenY)/cos(pi/2-ang)); elseif ang>=pi/2 && ang<ang_dl R=abs((h-cenY)/cos(pi/2+ang)); elseif ang>=ang_dl && ang<=pi R=abs(cenX/cos(pi-ang)); end [junk index]=min(abs(ang-lineAng)); %距離最近的弧度 newR=lineR(index); ss=R*r/newR; %縮減擴充套件比例係數 xx=round((ss*cos(ang)+cenX)); yy=round((ss*sin(ang)+cenY)); if xx>=1 && xx<=w && yy>=1 && yy<=h imgn(y,x)=img(yy,xx); end end end imshow(img); figure;imshow(mask_line); figure;imshow(imgn,[])
題外話:
今天等了一天在京東訂的kindle,到下午5點都還沒送來,最後發現竟然是手機沒訊號,沒有收到送貨通知。
中國移動一定是看我用的2G卡,又沒開上網功能,欺負人,不給優先順序。
如果收到貨,也許現在正在玩kindle,就不會有這篇文章了。