matlab练习程序(透视投影,把lena贴到billboard上)

时间:2023-02-13 22:54:18

本练习程序是受到了这个老外博文的启发,感觉挺有意思,就尝试了一下。他用的是opencv,我这里用的是matlab。

过去写过透视投影,当时是用来做倾斜校正的,这次同样用到了透视投影,不过更有意思,是将一张图像贴到另一张图像上。

两个透视投影都需要先计算投影矩阵,倾斜校正那一篇是通过解线性方程组求的变换矩阵,而这一篇是通过奇异值分解求的变换矩阵。

为了对齐两张图像,还需要对投影后的图像做一次仿射变换,其实就是坐标平移。

这里做投影和仿射直接调用了matlab的系统函数,方便一些。

还是先介绍下如何投影吧:

比如我们解单应性方程组或奇异值分解得到了投影矩阵:

matlab练习程序(透视投影,把lena贴到billboard上)

那么变换方程就可以写为:

matlab练习程序(透视投影,把lena贴到billboard上)

matlab练习程序(透视投影,把lena贴到billboard上)

其中,x,y为原图像像素坐标,X,Y为目标图像像素坐标。

做一些正反点匹配变换的时候我会用这个公式,不过大多数情况下在做图像投影的时候,我并不用上面的公式,而是用下面这个公式:

matlab练习程序(透视投影,把lena贴到billboard上)

matlab练习程序(透视投影,把lena贴到billboard上)

其中,x,y为原图像像素坐标,X,Y为目标图像像素坐标。

第一个公式计算后图像会出现空洞,第二个公式计算量明显变大了,各有利弊吧。

这么复杂的一个公式,我可推不出来,是用Mathematica推的,这个软件真是极大的提高了我的效率。

话说matlab应该也能推,不过matlab的符号计算毕竟不是强项,我也就没去了解matlab的这项功能。

看看效果吧。

原图:

matlab练习程序(透视投影,把lena贴到billboard上)

广告牌:

matlab练习程序(透视投影,把lena贴到billboard上)

结果:

matlab练习程序(透视投影,把lena贴到billboard上)

matlab代码如下:

main.m

clear all;close all;clc;

img1
=imread('lena.jpg');
[h1 w1]
=size(img1);
mask
=uint8(ones(h1,w1)); %二值模板,方便最后的合成

img2
=imread('pai.jpg');
[h2 w2]
=size(img2);

imshow(img1);
figure;imshow(img2);

p1
=[1,1;w1,1;1,h1;w1,h1];
p2
=ginput(); %依次点击公告牌左上、右上、左下、右下

T
=calc_homography(p1,p2); %计算单应性矩阵
T
=maketform('projective',T); %投影矩阵

[imgn X Y]
=imtransform(img1,T); %投影
mask
=imtransform(mask,T);

T2
=eye(3);
if X(1)>0, T2(3,1)= X(1); end
if Y(1)>0, T2(3,2)= Y(1); end
T2
=maketform('affine',T2); %仿射矩阵

imgn
=imtransform(imgn,T2,'XData',[1 w2],'YData',[1 h2]); %仿射
mask
=imtransform(mask,T2,'XData',[1 w2],'YData',[1 h2]);

img
=img2.*(1-mask)+imgn.*mask; %合成
figure;imshow(img,[])

calc_homography

function T = calc_homography(points1, points2)

xaxb
= points2(:,1) .* points1(:,1);
xayb
= points2(:,1) .* points1(:,2);
yaxb
= points2(:,2) .* points1(:,1);
yayb
= points2(:,2) .* points1(:,2);

A
= zeros(size(points1, 1)*2, 9);
A(
1:2:end,3) = 1;
A(
2:2:end,6) = 1;
A(
1:2:end,1:2) = points1;
A(
2:2:end,4:5) = points1;
A(
1:2:end,7) = -xaxb;
A(
1:2:end,8) = -xayb;
A(
2:2:end,7) = -yaxb;
A(
2:2:end,8) = -yayb;
A(
1:2:end,9) = -points2(:,1);
A(
2:2:end,9) = -points2(:,2);

[junk1,junk2,V]
= svd(A);
h
= V(:,9) ./ V(9,9);
T
= reshape(h,3,3);
end