首页 > 解决方案 > 如何在 Matlab 中仅使用 affine2d 和 transformPointsForward 旋转图像?

问题描述

我想在 Matlab 中旋转(30 度)图像,但不使用 imwarp、imtranslate、imrotate、imresize。

我的代码如下:

image = imread('image.jpg');
theta = 30;
tform = affine2d([cosd(theta) sind(theta) 0; -sind(theta) cosd(theta) 0; 0 0 1]);
[X,Y] = transformPointsForward(tform,1:800,1:800);

我相信我应该使用 imref2d,但我不完全确定如何使用。如何分配新坐标?我希望其余空间(由图像使用)为黑色(像素值 = 0)。

标签: imagematlabimage-translation

解决方案


正确的做法并不是那么简单。

  • 您帖子中的旋转矩阵是“居中”的 - (0,0) 是中心坐标。
    我们需要变换矩阵,其中 (1,1) 是左上角坐标。
  • 您需要转换图像的所有坐标。
    在您的帖子中,您仅转换坐标(1,1),(2,2),(3,3)...
  • 使用前向变换会创建“空洞”——目标图像中的所有像素都不会被填充。
    我们需要使用反向变换,并且对于每个目标像素,获取源像素的坐标(目标到源的变换被认为是“反向变换”)。
    使用逆变换transformPointsForward等价于反向变换。
    注意:您的转换矩阵实际上是“反向转换”。

以下是解决方法(请阅读评论):

I = rgb2gray(imread('peppers.png')); % Read sample image and convert to gray.

[rows, cols] = size(I);

theta = 30;

% The rotation matrix is "centered" - coordinate (0, 0) is the center:
cT = [cosd(theta) -sind(theta) 0; sind(theta) cosd(theta) 0; 0 0 1];

top2cen = [1          0          0
           0          1          0
           (cols+1)/2 (rows+1)/2 1];
       
cen2top = [1            0          0
           0            1          0
           -(cols+1)/2 -(rows+1)/2 1];

% We need the rotation matrix to be "top left" - coordinate (1, 1) is the top left coordinate:
T = cen2top*cT*top2cen; % Note: you don't really need to use matrix multiplications for solving this.

tform = affine2d(T);

% All the combinations of u,v coordinates
[U, V] = meshgrid(1:cols, 1:rows);

% Transform all the (u, v) coordinates of the input I.
[X, Y] = transformPointsForward(tform, U, V);

% Round the coordinates - the interpolation method is going to Nearest Neighbor.
X = round(X);
Y = round(Y);

J = zeros(size(I), 'like', I);

% Limit the X,Y coordinates to the valid range.
limX = max(min(X, cols), 1);
limY = max(min(Y, rows), 1);

% Copy the (u,v) pixel in I to position (x,y) in J.
J(sub2ind(size(I), limY, limX)) = I(sub2ind(size(I), V, U));

% Oops... J has many holes...
figure;imshow(J);
imwrite(J, 'fwJ.png');

% Correct way:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% We must inverse the transformation - use backward transformation instead of forward transformation.
%cT = inv([cosd(theta) -sind(theta) 0; sind(theta) cosd(theta) 0; 0 0 1]);
cT = [cosd(theta) sind(theta) 0; -sind(theta) cosd(theta) 0; 0 0 1]; % Inverse transformation matrix.

% Repeate the process with inversed transformation.
T = cen2top*cT*top2cen;
tform = affine2d(T);
[U, V] = meshgrid(1:cols, 1:rows);

% Transform all the (x, y) coordinates of the input I.
[X, Y] = transformPointsForward(tform, U, V);  % Name the coordinates U, V

% Round the coordinates - the interpolation method is going to Nearest Neighbor.
X = round(X);
Y = round(Y);

J = zeros(size(I), 'like', I);

% Limit the X,Y coordinates to the valid range.
limX = max(min(X, cols), 1);
limY = max(min(Y, rows), 1);

J(sub2ind(size(I), V, U)) = I(sub2ind(size(I), limY, limX));

% Zero the margins (place zeros where X, Y are outside of the valid range):
J((X < 1) | (Y < 1) | (X > cols) | (Y > rows)) = 0;

figure;imshow(J)
imwrite(J, 'J.png');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% Testing
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Reference:
K = imrotate(I, 30, 'nearest', 'crop');
figure;imshow(K)

% Display the difference from imrotate (images are equal).
figure;imagesc(double(K) - double(J));
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

正向变换的结果(错误的方式):
在此处输入图像描述

后向变换的结果(正确的方式):
在此处输入图像描述


推荐阅读