使用控制点扭曲图像
Warping an image using control points
我想根据从 here:
中提取的方案使用控制点转换图像
A
和 B
包含源和目标顶点的坐标。
我计算变换矩阵为:
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');
到这里它似乎正常工作,因为(使用归一化坐标)源顶点产生它的目标顶点:
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
问题是 imtransform
产生了意外的结果:
Z = imtransform(X,T,'XData',[1 info.Width], 'YData',[1 info.Height]);
imwrite(Z,'projective.png');
如何使用 imtransform
来产生我预期的结果?:
是否有其他方法可以实现?
您必须 "adapt" 控制点指向您正在处理的图像的大小。我这样做的方法是计算 A
中控制点的角与源图像的角之间的仿射变换(最好使这些点按相同的顺时针顺序排列)。
我应该指出的一件事是矩阵中点的顺序 A
与您显示的图片不匹配,所以我在下面的代码中修复了它...
这是估计单应性的代码(在 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
我得到:
>> H
H =
-0.3268 0.6419 -0.0015
-0.4871 0.4667 0.0009
324.0851 -221.0565 1.0000
现在让我们想象一下这些点:
% 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
最后我们可以对源图像应用转换:
% transform input image and show result
J = imtransform(I, T);
figure(2)
subplot(121), imshow(I), title('image')
subplot(122), imshow(J), title('warped')
您的问题是您在 imtransform
中指定 XData
和 YData
时不小心裁剪了输出图像。一种选择是使用 tformfwd
转换 A
来计算有效的 XData
和 YData
范围。
[U,V] = tformfwd(T, A(:,1), A(:,2));
Z = imtransform(X,T,'XData',[min(U) max(U)], 'YData', [min(V) max(V)]);
我想根据从 here:
中提取的方案使用控制点转换图像A
和 B
包含源和目标顶点的坐标。
我计算变换矩阵为:
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');
到这里它似乎正常工作,因为(使用归一化坐标)源顶点产生它的目标顶点:
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
问题是 imtransform
产生了意外的结果:
Z = imtransform(X,T,'XData',[1 info.Width], 'YData',[1 info.Height]);
imwrite(Z,'projective.png');
如何使用 imtransform
来产生我预期的结果?:
是否有其他方法可以实现?
您必须 "adapt" 控制点指向您正在处理的图像的大小。我这样做的方法是计算 A
中控制点的角与源图像的角之间的仿射变换(最好使这些点按相同的顺时针顺序排列)。
我应该指出的一件事是矩阵中点的顺序 A
与您显示的图片不匹配,所以我在下面的代码中修复了它...
这是估计单应性的代码(在 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
我得到:
>> H
H =
-0.3268 0.6419 -0.0015
-0.4871 0.4667 0.0009
324.0851 -221.0565 1.0000
现在让我们想象一下这些点:
% 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
最后我们可以对源图像应用转换:
% transform input image and show result
J = imtransform(I, T);
figure(2)
subplot(121), imshow(I), title('image')
subplot(122), imshow(J), title('warped')
您的问题是您在 imtransform
中指定 XData
和 YData
时不小心裁剪了输出图像。一种选择是使用 tformfwd
转换 A
来计算有效的 XData
和 YData
范围。
[U,V] = tformfwd(T, A(:,1), A(:,2));
Z = imtransform(X,T,'XData',[min(U) max(U)], 'YData', [min(V) max(V)]);