2013-10-12 60 views
1

我正在开发一个简单的算法来使用关键点和delaunay三角测量来变形两个图像。这个想法应该很简单:Delaunay三角测量图像变形

  • 信源选择控制点
  • 选择目标控制点
  • 获取源和目标德洛内三角框架
  • 每个像素的源图像中
    • 得到与像素所在的源三角形相关的像素重心坐标
    • 获得与目的地t有关的像素重心坐标使用关系Px = w1 * v0x + w2 * v1x + w3 * v2x(对于y和目标像素相同)指定OUT [PdestX,PdestY] = IN [Px,Py]的像素位于的棱纹
    • 。 。

但它不工作X_X这是我的matlab源:

function out = myMorph(im1, p_source, p_dest, tri_source, tri_dest) 

[h w] = size(im1); 

%get single column vectors for source and destination image control points 
Psource_x = p_source(:,1); 
Psource_y = p_source(:,2); 
Pdest_x  = p_dest(:,1); 
Pdest_y  = p_dest(:,2); 

%for each intermediate frame... 

out = zeros(size(im1)); 

%get triangles. Each array is 3n x 2, where n is the number of triangles 
triangles_source = []; 
triangles_dest = []; 
for i= 1 : size(tri_source,1) 
triangle_s = getTriangle(Psource_x,Psource_y,tri_source,i); 
triangle_d = getTriangle(Pdest_x,Pdest_y,tri_dest,i); 

triangles_source = cat(1,triangles_source,triangle_s); 
triangles_dest = cat(1,triangles_dest,triangle_d); 
end 



%iterate each pixel 
for x=1:h 
for y=1:w 

    %get the source and destination triangle for pixel [x y] 

    %source triangle 
    for t = 1 : 3 : size(triangles_source, 1)-2 

     [w1,w2,w3,inTriangle] = inTri(x,y, ... 
            triangles_source(t,1),triangles_source(t,2), ... 
            triangles_source(t+1,1),triangles_source(t+1,2), ... 
            triangles_source(t+2,1),triangles_source(t+2,2)); 
     if(inTriangle == 1) 
      break; %point [x,y] must belong to one (and only) triangle 
     end 
    end 

    %source triangle 
    for k = 1 : 3 : size(triangles_dest, 1)-2 
     [w1d,w2d,w3d,inTriangleD] = inTri(x,y, ... 
            triangles_dest(k,1),triangles_dest(k,2), ... 
            triangles_dest(k+1,1),triangles_dest(k+1,2), ... 
            triangles_dest(k+2,1),triangles_dest(k+2,2)); 
     if(inTriangleD == 1) 
      break; 
     end 
    end 

    v_source = [w1*triangles_source(t,1) + ... 
       w2*triangles_source(t+1,1) + ... 
       w3*triangles_source(t+2,1), ... 
       w1*triangles_source(t,2) + ... 
       w2*triangles_source(t+1,2) + ... 
       w3*triangles_source(t+2,2)]; 

    v_dest = [w1d*triangles_dest(k,1) + ... 
       w2d*triangles_dest(k+1,1) + ... 
       w3d*triangles_dest(k+2,1),... 
       w1d*triangles_dest(k,2) + ... 
       w2d*triangles_dest(k+1,2) + ... 
       w3d*triangles_dest(k+2,2)]; 


    if(inTriangle ~= 1 && inTriangleD ~= 1) 
     continue; 
    end 

    v_source = round(v_source); 
    v_dest  = round(v_dest); 

    if(v_source(1)>0 && v_source(1) <= h && ... 
     v_source(2)>0 && v_source(2) <= w && ... 
     v_dest(1)>0 && v_dest(1) <= h && ... 
     v_dest(2)>0 && v_dest(2) <= w) 

    disp('pixel warped') 
    out(v_dest(1),v_dest(2)) = im1(v_source(1),v_source(2)); 
    end 
    % else 
    % out(x,y) = im1(x,y); 

end 
end 

这些是得到控制点

%Get control points used to morph im into another image 
%im      -> source image 
%im2     -> destination image 
%linesNum    -> number of lines 
function [P] = getControlPoints(im, controlPtsNum) 

close all 

P = zeros(controlPtsNum, 2); 

%select lines from source image 
figure; 
imshow(im,[]);title('select control points') 

for i=1 : controlPtsNum 
    %get source control point 
[x,y] = ginput(1); 
    P(i,:) = [x,y]; 

    hold on 
    plot(x,y,'o','Color','r'); 
    hold off 
end 



%Get control points used to morph im into another image and do delaunay 
%triangulation using the control points 
%im      -> source image 
%im2     -> destination image 
%controlPtsNum   -> number of control points 
function [P,tri] = getControlPointsAndTriangulate(im, controlPtsNum) 

P = getControlPoints(im, controlPtsNum); 

[h w] = size(im); 

%Add corners to control points 
P = cat(1, P, [1 1]); 
P = cat(1, P, [w 1]); 
P = cat(1, P, [1 h]); 
P = cat(1, P, [w h]); 

tri = delaunay(P(:,1),P(:,2)); 

hold on 
triplot(tri,P(:,1),P(:,2)) 
hold on 

这个功能效用函数(我在网上找到),测试一个点是否位于给定的三角形上,并返回u,v,w值:

function [w1,w2,w3,r] = inTri(vx, vy, v0x, v0y, v1x, v1y, v2x, v2y) 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
% inTri checks whether input points (vx, vy) are in a triangle whose 
% vertices are (v0x, v0y), (v1x, v1y) and (v2x, v2y) and returns the linear 
% combination weight, i.e., vx = w1*v0x + w2*v1x + w3*v2x and 
% vy = w1*v0y + w2*v1y + w3*v2y. If a point is in the triangle, the 
% corresponding r will be 1 and otherwise 0. 
% 
% This function accepts multiple point inputs, e.g., for two points (1,2), 
% (20,30), vx = (1, 20) and vy = (2, 30). In this case, w1, w2, w3 and r will 
% be vectors. The function only accepts the vertices of one triangle. 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
v0x = repmat(v0x, size(vx,1), size(vx,2)); 
v0y = repmat(v0y, size(vx,1), size(vx,2)); 
v1x = repmat(v1x, size(vx,1), size(vx,2)); 
v1y = repmat(v1y, size(vx,1), size(vx,2)); 
v2x = repmat(v2x, size(vx,1), size(vx,2)); 
v2y = repmat(v2y, size(vx,1), size(vx,2)); 
w1 = ((vx-v2x).*(v1y-v2y) - (vy-v2y).*(v1x-v2x))./... 
((v0x-v2x).*(v1y-v2y) - (v0y-v2y).*(v1x-v2x)+eps); 
w2 = ((vx-v2x).*(v0y-v2y) - (vy-v2y).*(v0x-v2x))./... 
((v1x-v2x).*(v0y-v2y) - (v1y-v2y).*(v0x-v2x)+eps); 
w3 = 1 - w1 - w2; 
r = (w1>=0) & (w2>=0) & (w3>=0) & (w1<=1) & (w2<=1) & (w3<=1); 

有什么建议吗? 再见!

回答

2

我无法在代码中重现错误,因为我没有输入数据集,但是,根据您的描述,您可能会遇到与我尝试通过三角测量变形图像时相同的问题昨天:

源三角测量和目标三角测量中三角形的数量是不同

这可能是你在你的步骤描述什么原因造成的:

  1. 与源控制点进行Delaunay三角,得到了三角形网格
  2. 与目标控制点进行Delaunay三角,得到了三角形网格

Delaunay三角是太聪明了,它使用最少的NU用于三角测量的三角形的mbers。它不知道步骤2中的控制点是从步骤1中的控制点“转换而来”的。因此步骤1和步骤2中的三角形网格可能包含不同数量的三角形!下面是一个例子,如何来解决这个问题:

Example.

比方说,你已经构建的控制点,“源CP”和“目的地CP” 2名列表。 “源CP”是情况A中的红点。“目标CP”是情况B和C(它们相同)中的红点。

通过在“源CP”上执行Delaunay Triangulation来获得案例A.

通过在“目标CP”上执行Delaunay Triangulation来获得案例B.

请参阅?案例B比案例A少了1个三角形!如果发生这种情况,你可以在例的三角网和B.

一种解决方法是让案件C具有相同邻接表和相同数量的三角形的情况A的使用三角名单不变形,那么你可以用成对的三角形到三角形的仿射变换方法进行图像变形。

案例C是由刚刚在移动情形A一个控制点,但保持相同的邻接表获得。

当然,重叠的三角形现在已经成为一个新问题。我认为你可以放置扭曲的大小等约束来防止三角形重叠。此外,您发布的三角形相交测试代码通过返回列表中与查询点相交的第一个三角形的三角形ID来考虑重叠三角形。

所以问题是你只需要对每个源 - 目的地转换对执行一次Delaunay Triangulation

希望这会有所帮助!

+0

是的,它帮助了我=)我注意到三角形的数量从一帧到另一帧。实际上,对于我需要的东西,我留下了变形(但我会做到这一点!)基于光流的帧插值,并且它非常容易和计算便宜! –