Computing a matrix which transforms a quadrangle to another quadrangle in 2D

谁说胖子不能爱 提交于 2019-12-04 08:59:17

Using the data you posted:

P = [px(:) py(:)];
Q = [qx(:) qy(:)];

Compute the transformation:

H = Q/P;

apply the transformation:

Q2 = H*P;

Compare the results:

err = Q2-Q

output:

err =
   7.1054e-15   7.1054e-15
  -3.5527e-15  -3.5527e-15
  -1.4211e-14  -2.1316e-14
   1.4211e-14   1.4211e-14

which is zeros for all intents and purposes..


EDIT:

So as you pointed out in the comments, the above method will not compute the 3x3 homography matrix. It simply solves the system of equations with as many equations as points provided:

H * A = B   -->   H = B*inv(A)   -->   H = B/A (mrdivide)

Otherwise, MATLAB has the CP2TFORM function in the image processing toolbox. Here is an example applied to the image shown:

%# read illustration image
img = imread('http://i.stack.imgur.com/ZvaZK.png');
img = imcomplement(im2bw(img));

%# split into two equal-sized images
imgs{1} = img(:,fix(1:end/2));
imgs{2} = img(:,fix(end/2:end-1));

%# extract the four corner points A and B from both images
C = cell(1,2);
for i=1:2
    %# some processing
    I = imfill(imgs{i}, 'holes');
    I = bwareaopen(imclearborder(I),200);
    I = imfilter(im2double(I), fspecial('gaussian'));

    %# find 4 corners
    C{i} = corner(I, 4);

    %# sort corners in a consistent way (counter-clockwise)
    idx = convhull(C{i}(:,1), C{i}(:,2));
    C{i} = C{i}(idx(1:end-1),:);
end

%# show the two images with the detected corners
figure
for i=1:2
    subplot(1,2,i), imshow(imgs{i})
    line(C{i}(:,1), C{i}(:,2), 'Color','r', 'Marker','*', 'LineStyle','none')
    text(C{i}(:,1), C{i}(:,2), num2str((1:4)'), 'Color','r', ...
        'FontSize',18, 'Horiz','left', 'Vert','bottom')
end

With the corners detected, now we can obtain the spatial transformation:

%# two sets of points
[A,B] = deal(C{:});

%# infer projective transformation using CP2TFORM
T = cp2tform(A, B, 'projective');

%# 3x3 Homography matrix
H = T.tdata.T;
Hinv = T.tdata.Tinv;

%# align points in A into B
X = tformfwd(T, A(:,1), A(:,2));

%# show result of transformation
line(X([1:end 1],1), X([1:end 1],2), 'Color','g', 'LineWidth',2)

The result:

>> H = T.tdata.T
H =
      0.74311    -0.055998    0.0062438
      0.44989      -1.0567   -0.0035331
      -293.31       62.704      -1.1742

>> Hinv = T.tdata.Tinv
Hinv =
       -1.924     -0.42859   -0.0089411
      -2.0585      -1.2615   -0.0071501
       370.68       39.695            1

We can confirm the calculation ourselves:

%# points must be in Homogenous coordinates (x,y,w)
>> Z = [A ones(size(A,1),1)] * H;
>> Z = bsxfun(@rdivide, Z, Z(:,end))   %# divide by w
Z =
          152           57            1
          219          191            1
           62          240            1
           92          109            1

which maps to the points in B:

%# maximum error
>> max(max( abs(Z(:,1:2)-B) ))
ans =
   8.5265e-14

You can try the cp2tform function, which infers spatial transformation from control point pairs. Since parallel is not preserved in your case, you should set the transformtype to be 'projective'. More info is here

You can use the DLT algorithm for this purpose. There are MATLAB routines available for doing that in Peter Kovesi's homepage.

Combine all the coordinates into column vectors. In 2D case they are: ax, ay, bx, by;

Define:

A = [ax, ay];
B = [bx, by];
input = [ones(size(A, 1), 1), A];

Calculate transformation matrix:

H = input \ B;

If you need to apply it on new observations A_new:

input_new = [ones(size(A_new, 1), 1), A_new];
B_new = input_new * H;

Edit: you can also calculate H by: H = inv(input' * input) * input' * B; but \ does if safely.

Jacob

I discussed a related problem in an answer to another SO question (includes a MATLAB solution). In the linked problem, the output quadrilateral was a rectangle, but my answer handles the general problem.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!