I want to convert an image using control points according to this scheme extracted from here:
A
and B
contains the coordinates of the source an target vertices.
I am computing the transformation matrix as:
A = [51 228; 51 127; 191 127; 191 228];
B = [152 57; 219 191; 62 240; 92 109];
X = imread('rectangle.png');
info = imfinfo('rectangle.png');
T = cp2tform(A,B,'projective');
Up to here it seems to properly work, because (using normalized coordinates) a source vertex produces its target vertex:
H = T.tdata.T;
> [51 228 1]*H
ans =
-248.2186 -93.0820 -1.6330
> [51 228 1]*H/ -1.6330
ans =
152.0016 57.0006 1.0000
The problem is that imtransform
produces an unexpected result:
Z = imtransform(X,T,'XData',[1 info.Width], 'YData',[1 info.Height]);
imwrite(Z,'projective.png');
How can I use imtransform
to produce this my expected result?:
Is there an alternative way to achieve it?
Photoshop's warp tool lets you do just that – warp an image. You can take a selection and drag to reshape it however you want. The warp tool can be accessed by going to Edit at the top of the screen, then selecting Transform, and then Warp. You can also access it by clicking Ctrl+T on a PC or Command+T on a Mac.
The Warp Brush tool can be used to create caricatures. You can also warp images by using a grid. When you use the Mesh Warp tool, a grid or mesh is placed on the image. The grid intersections have mesh points, or nodes, that you drag to create deformations.
Image warping is the process of digitally manipulating an image such that any shapes portrayed in the image have been significantly distorted. Warping may be used for correcting image distortion as well as for creative purposes (e.g., morphing). The same techniques are equally applicable to video.
Warping is the distortion of one static image to produce another static image. In contrast, morphing refers to transforming one image to another through a series of intermediate images, which, when projected successively, give the impression of a gradual “metamorphosis.” Morphing is, therefore, a computer movie.
You have to "adapt" the control points to the size of the image you're working with. The way I did this is by computing an affine transformation between the corners of the control points in A
and the corners of the source image (preferrably you want to make the points are in the same clockwise order).
One thing I should point out is that the order of points in your matrix A
does not match the picture you've shown, so I fixed that in the code below...
Here is the code to estimate the homography (tested in MATLAB):
% initial control points
A = [51 228; 51 127; 191 127; 191 228];
B = [152 57; 219 191; 62 240; 92 109];
A = circshift(A, [-1 0]); % fix the order of points to match the picture
% input image
%I = imread('peppers.png');
I = im2uint8(checkerboard(32,5,7));
[h,w,~] = size(I);
% adapt control points to image size
% (basically we estimate an affine transform from 3 corner points)
aff = cp2tform(A(1:3,:), [1 1; w 1; w h], 'affine');
A = tformfwd(aff, A);
B = tformfwd(aff, B);
% estimate homography between A and B
T = cp2tform(B, A, 'projective');
T = fliptform(T);
H = T.tdata.Tinv
I get:
>> H
H =
-0.3268 0.6419 -0.0015
-0.4871 0.4667 0.0009
324.0851 -221.0565 1.0000
Now let's visualize the points:
% check by transforming A points into B
%{
BB = [A ones(size(A,1),1)] * H; % convert to homogeneous coords
BB = bsxfun(@rdivide, BB, BB(:,end)); % convert from homogeneous coords
%}
BB = tformfwd(T, A(:,1), A(:,2));
fprintf('error = %g\n', norm(B-BB));
% visually check by plotting control points and transformed A
figure(1)
subplot(121)
plot(A([1:end 1],1), A([1:end 1],2), '.-', 'MarkerSize',20, 'LineWidth',2)
line(BB([1:end 1],1), BB([1:end 1],2), 'Color','r', 'Marker','o')
text(A(:,1), A(:,2), num2str((1:4)','a%d'), ...
'VerticalAlign','top', 'HorizontalAlign','left')
title('A'); legend({'A', 'A*H'}); axis equal ij
subplot(122)
plot(B([1:end 1],1), B([1:end 1],2), '.-', 'MarkerSize',20, 'LineWidth',2)
text(B(:,1), B(:,2), num2str((1:4)','b%d'), ...
'VerticalAlign','top', 'HorizontalAlign','left')
title('B'); legend('B'); axis equal ij
Finally we can apply the transformation on the source image:
% transform input image and show result
J = imtransform(I, T);
figure(2)
subplot(121), imshow(I), title('image')
subplot(122), imshow(J), title('warped')
Your problem is that you accidentally cropped the output image when you specified your XData
and YData
in imtransform
. One option would be to use tformfwd
with to transform A
to compute the valid XData
and YData
ranges.
[U,V] = tformfwd(T, A(:,1), A(:,2));
Z = imtransform(X,T,'XData',[min(U) max(U)], 'YData', [min(V) max(V)]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With