注: 本文演算法參考大佬 grafx 的這篇博客:
影像處理演算法之水面倒影特效
由于本文使用MATLAB復現,因此很多語法上會顯得比較簡潔,同時本博文對原大佬文章部分內容進行了改寫,詳見本文:
0效果展示



1影像翻轉及白化
匯入影像: 這部分其實沒啥好說的:
% 圖片匯入
oriPic=imread('test.jpg');
[Row,Col,~]=size(oriPic);

翻轉及白化影像:
翻轉就是單純的將行索引倒過來;
白化就是將當前像素的顏色按比例和白色取個帶權均值,行索引越大白色權重也越大,影像也就越白,
% 圖片翻轉及白化 ==========================================================
whiteMat=((1:Row)./Row./1.2)'*ones(1,Col); % 白化比例矩陣
flipPic=zeros(Row,Col,3); % 翻轉后矩陣初始化
for i=1:3
tempChannel=double(oriPic(:,:,i)); % 獲得通道圖
tempChannel=tempChannel(end:-1:1,:); % 翻轉
tempChannel=tempChannel.*(1-whiteMat)+255.*whiteMat; % 白化
flipPic(:,:,i)=tempChannel;
end

當然如果我們將這一行:
tempChannel=tempChannel.*(1-whiteMat)+255.*whiteMat;
改寫為:
tempChannel=tempChannel.*(1-whiteMat)+0.*whiteMat;
就變成了一個黑化的程序:

當然你也可以嘗試其他顏色,例如將整段改寫為:
Color=[255,0,0];
colorMat=((1:Row)./Row./1.2)'*ones(1,Col); % 比例矩陣
flipPic=zeros(Row,Col,3); % 翻轉后矩陣初始化
for i=1:3
tempChannel=double(oriPic(:,:,i)); % 獲得通道圖
tempChannel=tempChannel(end:-1:1,:); % 翻轉
tempChannel=tempChannel.*(1-colorMat)+Color(i).*colorMat; % 漸變
flipPic(:,:,i)=tempChannel;
end
imshow(uint8(flipPic))

2波紋影像構造
生成噪聲并模糊
noiseMat=ones(Row,Col);
noiseMat=imnoise(noiseMat,'gaussian',0,5); % 噪聲添加
gaussOpt=fspecial('gaussian',[3 3],1);
noiseMat=imfilter(noiseMat,gaussOpt);
噪聲圖:

模糊后噪聲圖:

浮雕特效
實際上浮雕特效就是用以下類似形式的矩陣對影像進行卷積,卷積結果在加上RGB范圍的均值,[0,1]區間就加0.5,[0,255]區間就加128:
[
1
0
0
0
0
0
0
0
?
1
]
[
2
0
2
0
0
0
?
2
0
?
2
]
\begin{bmatrix} 1 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & -1 \end{bmatrix} \begin{bmatrix} 2 & 0 & 2 \\ 0 & 0 & 0 \\ -2 & 0 & -2 \end{bmatrix}
???100?000?00?1???????20?2?000?20?2????
數值和位置不重要,重要的是相對位置互為相反數,浮雕程序描述如下:
H=[cos(pi+pi/4),0,cos(pi-pi/4);
cos(pi+2*pi/4),0,cos(pi-2*pi/4);
cos(pi+3*pi/4),0,cos(pi-3*pi/4)];
noiseMat=imfilter(noiseMat,H,'conv')+0.5;
noiseMat=noiseMat.*255;
noiseMat(noiseMat<0)=0;

透視變換
就是近大遠小,這里為了方便起見只在橫向方向上做了近大遠小的拉伸,豎直方向進行了等比例拉伸,因而不是嚴格意義上的透視變換:

如圖所示實際操作就是把左側藍色區域拉伸成右側藍色區域,并只選取紅框內部分,代碼如下:
% 影像透視變換 ============================================================
exNoiseMat=zeros(Row,Col);
% 橫向拉伸上下邊倍數
K1=10;K2=4;
for i=1:Row
for j=1:Col
k=K2+i*(K1-K2)/Row;
nJ=(j-(1+Col)/2)/k+(1+Col)/2;
if floor(nJ)==ceil(nJ)
nJ=round(nJ);
exNoiseMat(i,j)=noiseMat(i,nJ);
else
nJ1=floor(nJ);nJ2=ceil(nJ);
exNoiseMat(i,j)=noiseMat(i,nJ1)*(nJ2-nJ)+noiseMat(i,nJ2)*(nJ-nJ1);
end
end
end
% 豎向拉伸3倍并只取一部分
exNoiseMat=imresize(exNoiseMat,[3*Row,Col]);
exNoiseMat=exNoiseMat(end-Row+1:end,:);
exNoiseMat=uint8(exNoiseMat);

注: 如果原影像尺寸過大,水波就會過于密集,這時候可以適當調整放縮倍數或者將原影像重調大小到小一點的尺寸,
例如大波浪代碼:
% 影像透視變換 ============================================================
exNoiseMat=zeros(Row,Col);
K1=40;K2=10;
for i=1:Row
for j=1:Col
k=K2+i*(K1-K2)/Row;
nJ=(j-(1+Col)/2)/k+(1+Col)/2;
if floor(nJ)==ceil(nJ)
nJ=round(nJ);
exNoiseMat(i,j)=noiseMat(i,nJ);
else
nJ1=floor(nJ);nJ2=ceil(nJ);
exNoiseMat(i,j)=noiseMat(i,nJ1)*(nJ2-nJ)+noiseMat(i,nJ2)*(nJ-nJ1);
end
end
end
exNoiseMat=imresize(exNoiseMat,[8*Row,Col]);
exNoiseMat=exNoiseMat(end-Row+1:end,:);
exNoiseMat=uint8(exNoiseMat);
小波浪和大波浪:


3扭曲置換
這個,,,老朋友了,具體原理還是看這一篇叭:MATLAB 制作抖音同款含褶皺面料圖
% 扭曲置換 ================================================================
forePic=flipPic;
bkgPic=exNoiseMat;
exforePic=uint8(zeros(size(forePic)+[26,26,0]));
exforePic(14:end-13,14:end-13,1)=forePic(:,:,1);
exforePic(14:end-13,14:end-13,2)=forePic(:,:,2);
exforePic(14:end-13,14:end-13,3)=forePic(:,:,3);
for i=1:13
exforePic(i,14:end-13,:)=forePic(1,:,:);
exforePic(end+1-i,14:end-13,:)=forePic(end,:,:);
exforePic(14:end-13,i,:)=forePic(:,1,:);
exforePic(14:end-13,end+1-i,:)=forePic(:,end,:);
end
for i=1:3
exforePic(1:13,1:13,i)=forePic(1,1,i);
exforePic(end-13:end,end-13:end,i)=forePic(end,end,i);
exforePic(end-13:end,1:13,i)=forePic(end,1,i);
exforePic(1:13,end-13:end,i)=forePic(1,end,i);
end
newforePic=uint8(zeros(size(forePic)));
for i=1:size(bkgPic,1)
for j=1:size(bkgPic,2)
goffset=(double(bkgPic(i,j))-128)/10;
offsetLim1=floor(goffset)+13;
offsetLim2=ceil(goffset)+13;
sep1=goffset-floor(goffset);
sep2=ceil(goffset)-goffset;
c1=double(exforePic(i+offsetLim1,j+offsetLim1,:));
c2=double(exforePic(i+offsetLim2,j+offsetLim2,:));
if sep1==0
c=double(exforePic(i+offsetLim1,j+offsetLim1,:));
else
c=c2.*sep1+c1.*sep2;
end
newforePic(i,j,:)=c;
end
end


4影像拼接
就是把倆影像拼在一起,并把邊緣模糊一下:
% 影像拼接 ================================================================
resultPic(:,:,1)=[oriPic(:,:,1);newforePic(:,:,1)];
resultPic(:,:,2)=[oriPic(:,:,2);newforePic(:,:,2)];
resultPic(:,:,3)=[oriPic(:,:,3);newforePic(:,:,3)];
% imshow(resultPic)
% 邊緣模糊 ================================================================
gaussOpt=fspecial('gaussian',[3 3],0.5);
gaussPic=imfilter(resultPic,gaussOpt);
resultPic(Row-1:Row+2,:,1)=gaussPic(Row-1:Row+2,:,1);
resultPic(Row-1:Row+2,:,2)=gaussPic(Row-1:Row+2,:,2);
resultPic(Row-1:Row+2,:,3)=gaussPic(Row-1:Row+2,:,3);
imshow(resultPic)

5完整代碼
function mirrorDown
% @author slandarer
% 圖片匯入
oriPic=imread('test.jpg');
[Row,Col,~]=size(oriPic);
% 圖片翻轉及白化 ==========================================================
whiteMat=((1:Row)./Row./1.2)'*ones(1,Col); % 白化比例矩陣
flipPic=zeros(Row,Col,3); % 翻轉后矩陣初始化
for i=1:3
tempChannel=double(oriPic(:,:,i)); % 獲得通道圖
tempChannel=tempChannel(end:-1:1,:); % 翻轉
tempChannel=tempChannel.*(1-whiteMat)+255.*whiteMat; % 白化
flipPic(:,:,i)=tempChannel;
end
% imshow(uint8(flipPic))
% 噪聲圖構造(高斯噪聲及高斯模糊)===========================================
noiseMat=ones(Row,Col);
noiseMat=imnoise(noiseMat,'gaussian',0,5); % 噪聲添加
gaussOpt=fspecial('gaussian',[3 3],1);
noiseMat=imfilter(noiseMat,gaussOpt);
imshow(noiseMat)
H=[cos(pi+pi/4),0,cos(pi-pi/4);
cos(pi+2*pi/4),0,cos(pi-2*pi/4);
cos(pi+3*pi/4),0,cos(pi-3*pi/4)];
noiseMat=imfilter(noiseMat,H,'conv')+0.5;
noiseMat=noiseMat.*255;
noiseMat(noiseMat<0)=0;
% imshow(uint8(noiseMat))
% 影像透視變換 ============================================================
exNoiseMat=zeros(Row,Col);
K1=10;K2=4;
for i=1:Row
for j=1:Col
k=K2+i*(K1-K2)/Row;
nJ=(j-(1+Col)/2)/k+(1+Col)/2;
if floor(nJ)==ceil(nJ)
nJ=round(nJ);
exNoiseMat(i,j)=noiseMat(i,nJ);
else
nJ1=floor(nJ);nJ2=ceil(nJ);
exNoiseMat(i,j)=noiseMat(i,nJ1)*(nJ2-nJ)+noiseMat(i,nJ2)*(nJ-nJ1);
end
end
end
exNoiseMat=imresize(exNoiseMat,[6*Row,Col]);
exNoiseMat=exNoiseMat(end-Row+1:end,:);
exNoiseMat=uint8(exNoiseMat);
% imshow(exNoiseMat)
% 扭曲置換 ================================================================
forePic=flipPic;
bkgPic=exNoiseMat;
exforePic=uint8(zeros(size(forePic)+[26,26,0]));
exforePic(14:end-13,14:end-13,1)=forePic(:,:,1);
exforePic(14:end-13,14:end-13,2)=forePic(:,:,2);
exforePic(14:end-13,14:end-13,3)=forePic(:,:,3);
for i=1:13
exforePic(i,14:end-13,:)=forePic(1,:,:);
exforePic(end+1-i,14:end-13,:)=forePic(end,:,:);
exforePic(14:end-13,i,:)=forePic(:,1,:);
exforePic(14:end-13,end+1-i,:)=forePic(:,end,:);
end
for i=1:3
exforePic(1:13,1:13,i)=forePic(1,1,i);
exforePic(end-13:end,end-13:end,i)=forePic(end,end,i);
exforePic(end-13:end,1:13,i)=forePic(end,1,i);
exforePic(1:13,end-13:end,i)=forePic(1,end,i);
end
newforePic=uint8(zeros(size(forePic)));
for i=1:size(bkgPic,1)
for j=1:size(bkgPic,2)
goffset=(double(bkgPic(i,j))-128)/10;
offsetLim1=floor(goffset)+13;
offsetLim2=ceil(goffset)+13;
sep1=goffset-floor(goffset);
sep2=ceil(goffset)-goffset;
c1=double(exforePic(i+offsetLim1,j+offsetLim1,:));
c2=double(exforePic(i+offsetLim2,j+offsetLim2,:));
if sep1==0
c=double(exforePic(i+offsetLim1,j+offsetLim1,:));
else
c=c2.*sep1+c1.*sep2;
end
newforePic(i,j,:)=c;
end
end
% imshow(newforePic)
% 影像拼接 ================================================================
resultPic(:,:,1)=[oriPic(:,:,1);newforePic(:,:,1)];
resultPic(:,:,2)=[oriPic(:,:,2);newforePic(:,:,2)];
resultPic(:,:,3)=[oriPic(:,:,3);newforePic(:,:,3)];
% imshow(resultPic)
% 邊緣模糊 ================================================================
gaussOpt=fspecial('gaussian',[3 3],0.5);
gaussPic=imfilter(resultPic,gaussOpt);
resultPic(Row-1:Row+2,:,1)=gaussPic(Row-1:Row+2,:,1);
resultPic(Row-1:Row+2,:,2)=gaussPic(Row-1:Row+2,:,2);
resultPic(Row-1:Row+2,:,3)=gaussPic(Row-1:Row+2,:,3);
imshow(resultPic)
end
6其他效果展示




轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291740.html
標籤:其他
