计算机视觉课程设计实验报告
1.题 目: 图 像 变 形
2.组 员:曹英(E030201) 叶超(E030124) 李淑珍(E030104) 3.实验目的:掌握图像几何运算中变形算法
4.实验原理:对两幅图分别进行卷绕、插值,每幅图得到一序列图片,然后
对这些序列图片进行加权求和,得到一序列帧,再将其显示出来,就得到了由一幅图到另一幅图的变形。
5.实验步骤:对一幅图分别选4行4列的16个控制点,在每条边上进行五
等分,每条边形成六个点,加上原来的16个就是36个控制点,这样就把它分成了不规则的25小块,对每小块进行卷绕、插值,本实验我们用的是最近邻插值,目标控制点就是将图片分成标准并且相同大小的25小块的36个点。这样会得到一幅不规则图片,让它作为新的原图进行如前所述一样的处理,控制点都是这样自动产生的:一开始所选每个控制点到相应标准控制点等距离(本实验我们是分成9等分)产生一序列的36个控制点。这样每产生一幅图都对它进行相类似的处理,控制点的产生方法就是上面所说的那样。得到的一序列图片越来越接近原图,最后一幅与原图一样。这样我们就可以得到这样的一序列图片:原图,手工选控制点进行处理后得到的不规则图,循环产生控制点得到的越来越接近原图的9幅图(最后一幅与原图一样)。为了描述的方便,这里我把它编号为1_1到1_11。 对目标图进行与原图一样的处理。编号也类似,即2_1到2_11。
最后进行加权求和,第一帧是原图,第二帧是1_10与2_2加权求和,其中1_10的权值是0.9,2_2的权值是0.1,第三帧是1_9与2_3加权求和,其中1_9的权值是0.8,2_3的权值是0.2,……,第十帧是1_2与2_10加权求和,其中1_10的权值是0.1,2_2的权值是0.9,第十一帧是目标图。这样就得到了所要的结果。 这里需要说明的是两幅手工选择的控制点最好是那些有代表性的特征点,这样的话结果会更好。
下面的程序的源代码: clear all; clc; x1=imread('im1.jpg'); x2=imread('im2.jpg'); [m,n,p]=size(x1); subplot(2,2,1),imshow(x1); subplot(2,2,2),imshow(x2); x1=double(x1); x2=double(x2); newx=[]; newy=[]; %在图片上选36个点将图片分成标准并且相同大小的25小块 for k=1:36 newx(k)=fix((n/5))*(mod(k-1,6))+1; newy(k)=fix((m/5))*fix((k-1)/6)+1; end %对原图进行分块 for k=1:36 switch k case {1,2,3,4,5,6,7,12,13,18,19,24,25,30,31,32,33,34,35,36} %边界上的点还是标准的等分点 oldx1(k)=newx(k); oldy1(k)=newy(k); otherwise %在图片中选择4行4列的16个控制点 [oldx1(k),oldy1(k)]=ginput(1); hold on; subplot(2,2,1),plot(oldx1(k),oldy1(k),'o'); end end %对目标图进行分块,方法同上 for k=1:36 switch k case {1,2,3,4,5,6,7,12,13,18,19,24,25,30,31,32,33,34,35,36} oldxx1(k)=newx(k); oldyy1(k)=newy(k); otherwise [oldxx1(k),oldyy1(k)]=ginput(1); hold on; subplot(2,2,2),plot(oldxx1(k),oldyy1(k),'*'); end end %对第一张进行卷绕,插值 for i=1:29 newspic=[]; if mod(i,6)~=0 for j=1:4 %每个小块分别处理 if j==1 newspic=[1 newx(i) newy(i) newx(i)*newy(i)]; elseif j==2 newspic=[newspic;1 newx(i+1) newy(i) newx(i+1)*newy(i)]; elseif j==3 newspic=[newspic;1 newx(i) newy(i+6) newx(i)*newy(i+6)]; elseif j==4 newspic=[newspic;1 newx(i+1) newy(i+7) newx(i+1)*newy(i+7)]; end end oldx1_1=[oldx1(i);oldx1(i+1);oldx1(i+6);oldx1(i+7)]; %卷绕 oldy1_1=[oldy1(i);oldy1(i+1);oldy1(i+6);oldy1(i+7)]; cofx=inv(newspic)*oldx1_1; cofy=inv(newspic)*oldy1_1; for k=newy(i):newy(i+6) %进行最近邻插值 for l=newx(i):newx(i+1) for rgb=1:3 testx=[1,l,k,k*l]*cofx; testy=[1,l,k,k*l]*cofy; if round(testx)<1 | round(testy)<1 | round(testx)>n | round(testy)>m pic1(k,l,rgb)=0; else pic1(k,l,rgb)=x1(round(testy),round(testx),rgb); end end end end end end %后面的连续桢(9帧) for Q=1:9 for k=1:36 switch k case {1,2,3,4,5,6,7,12,13,18,19,24,25,30,31,32,33,34,35,36} oldx2(k)=newx(k); oldy2(k)=newy(k); otherwise %用循环控制产生新的控制点 oldx2(k)=(newx(k)-oldx1(k))*Q/9+oldx1(k); oldy2(k)=(newy(k)-oldy1(k))*Q/9+oldy1(k); end end for i=1:29 %下面是卷绕,插值,方法同上 newspic=[]; if mod(i,6)~=0 for j=1:4 if j==1 newspic=[1 newx(i) newy(i) newx(i)*newy(i)]; elseif j==2 newspic=[newspic;1 newx(i+1) newy(i) newx(i+1)*newy(i)]; elseif j==3 newspic=[newspic;1 newx(i) newy(i+6) newx(i)*newy(i+6)]; elseif j==4 newspic=[newspic;1 newx(i+1) newy(i+7) newx(i+1)*newy(i+7)]; end end oldx2_1=[oldx2(i);oldx2(i+1);oldx2(i+6);oldx2(i+7)]; oldy2_1=[oldy2(i);oldy2(i+1);oldy2(i+6);oldy2(i+7)]; cofx=inv(newspic)*oldx2_1; cofy=inv(newspic)*oldy2_1; for k=newy(i):newy(i+6) for l=newx(i):newx(i+1) for rgb=1:3 testx=[1,l,k,k*l]*cofx; testy=[1,l,k,k*l]*cofy; if round(testx)<1 | round(testy)<1 | round(testx)>n round(testy)>m pic2(k,l,rgb,Q)=0; else pic2(k,l,rgb,Q)=x1(round(testy),round(testx),rgb); end end end end end end end %对第二张进行卷绕,插值,方法同上 for i=1:29 newspic=[]; if mod(i,6)~=0 for j=1:4 if j==1 newspic=[1 newx(i) newy(i) newx(i)*newy(i)]; elseif j==2 newspic=[newspic;1 newx(i+1) newy(i) newx(i+1)*newy(i)]; elseif j==3 newspic=[newspic;1 newx(i) newy(i+6) newx(i)*newy(i+6)]; elseif j==4 newspic=[newspic;1 newx(i+1) newy(i+7) newx(i+1)*newy(i+7)]; end end oldxx1_1=[oldxx1(i);oldxx1(i+1);oldxx1(i+6);oldxx1(i+7)]; oldyy1_1=[oldyy1(i);oldyy1(i+1);oldyy1(i+6);oldyy1(i+7)]; cofx=inv(newspic)*oldxx1_1; cofy=inv(newspic)*oldyy1_1; for k=newy(i):newy(i+6) for l=newx(i):newx(i+1) for rgb=1:3 testx=[1,l,k,k*l]*cofx; | testy=[1,l,k,k*l]*cofy; if round(testx)<1 | round(testy)<1 | round(testx)>n round(testy)>m pic3(k,l,rgb,Q)=0; else pic3(k,l,rgb)=x2(round(testy),round(testx),rgb); end end end end end end %后面的连续桢 for Q=1:9 for k=1:36 switch k case {1,2,3,4,5,6,7,12,13,18,19,24,25,30,31,32,33,34,35,36} oldxx2(k)=newx(k); oldyy2(k)=newy(k); otherwise oldxx2(k)=(newx(k)-oldx1(k))*Q/9+oldxx1(k); oldyy2(k)=(newy(k)-oldy1(k))*Q/9+oldyy1(k); end end for i=1:29 newspic=[]; if mod(i,6)~=0 for j=1:4 if j==1 newspic=[1 newx(i) newy(i) newx(i)*newy(i)]; elseif j==2 newspic=[newspic;1 newx(i+1) newy(i) newx(i+1)*newy(i)]; elseif j==3 newspic=[newspic;1 newx(i) newy(i+6) newx(i)*newy(i+6)]; elseif j==4 newspic=[newspic;1 newx(i+1) newy(i+7) newx(i+1)*newy(i+7)]; end end oldxx2_1=[oldxx2(i);oldxx2(i+1);oldxx2(i+6);oldxx2(i+7)]; oldyy2_1=[oldyy2(i);oldyy2(i+1);oldyy2(i+6);oldyy2(i+7)]; cofx=inv(newspic)*oldxx2_1; cofy=inv(newspic)*oldyy2_1; for k=newy(i):newy(i+6) for l=newx(i):newx(i+1) | for rgb=1:3 testx=[1,l,k,k*l]*cofx; testy=[1,l,k,k*l]*cofy; if round(testx)<1 | round(testy)<1 | round(testx)>n | round(testy)>m pic4(k,l,rgb,Q)=0; else pic4(k,l,rgb,Q)=x2(round(testy),round(testx),rgb); end end end end end end end s1=size(pic1); s2=size(pic3); s(1)=min(s1(1),s2(1)); s(2)=min(s1(2),s2(2)); s(3)=min(s1(3),s2(3)); %对两幅图片产生的序列图进行加权求和,将结果放在一个4维数组中,产生11帧图像 picture(1:m,1:n,1:p,1)=x1; picture(1:s(1),1:s(2),1:s(3),2)=0.9*pic2(1:s(1),1:s(2),1:s(3),8)+0.1*pic3(1:s(1),1:s(2),1:s(3)); for i=3:9 picture(1:s(1),1:s(2),1:s(3),i)=(1.1-0.1*i)*pic2(:,:,:,10-i)+(i-1)*0.1*pic4(:,:,:,i-2); end picture(1:s(1),1:s(2),1:s(3),10)=0.1*pic1(1:s(1),1:s(2),1:s(3))+0.9*pic4(:,:,:,8); picture(1:m,1:n,1:p,11)=x2; picture=uint8(picture); for i=1:11 subplot(2,2,3),imshow(picture(:,:,:,i));pause(0.5); end mov=avifile('movie1.avi'); mov.fps=7; for i=1:11 mov=addframe(mov,picture(:,:,:,i)); end mov=close(mov); 6.实验结果图:
第一帧到最后一帧的结果分别是:
6.实验心得体会:
1.通过这个实验,最大的感受就是学的东西必须去用才能真正的理解,不动手的时候根本不知道种种问题的存在,找资料也很重要,通过找资料,才能产生一些想法,知道该如何下手,用各种算法去实现它,最后得到一个最满意的算法。编程也很重要,如果不会编程,有再好的算法也没有用。还有就是复杂度,不过本实验由于时间的关系,我们没有过多的考虑对程序代码进行优化,使它的运行时间最短。
2.本实验可以采用的原理有多种,这也让我们知道了做题之前理解原理才是最重要的 ,不能盲目的还没完全明白原理之前就开始动手编程,这样出来的效果不是我们要的效果,而且还会浪费很多时间!
就象刚开始我们采用的是10个控制点卷绕实现变形,但由于10个控制点的随即性,卷绕过程产生的图象扭曲地比较厉害,完全不是我们所要的效果。这就是我们没有透彻理解原理造成的!
之后我们又结合了同学的意见,采用了 如上的原理方法,处理过程中固定了边框,使之边框不会变形,变的只是中间图形的扭曲,再叠加产生最后帧图象,事实证明这种方法可行的,而且效果比较好。
因此通过这次实验,让我们明白了选择一个比较有效的算法原理,然后研究实现过程,这才是以后我们做题的关键所在!