Как я могу повернуть изображение, используя только affine2d и transformPointsForward в Matlab?
Я хотел бы повернуть (30 градусов) изображение в Matlab, но без использования 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).
1 ответ
Правильный способ сделать это не так уж и тривиально.
- Матрица вращения в вашем сообщении «центрирована» - (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));
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%