bilinear - Rotación de imagen por Matlab sin utilizar imrotate.
bilinear interpolation matlab (4)
El método que está utilizando (rotar por muestreo) es el más rápido y simple, pero también el menos preciso.
El mapa de rotación por área, como se indica a continuación ( this es una buena referencia), es mucho mejor para preservar el color.
Pero: tenga en cuenta que esto solo funcionará en imágenes en escala de grises / RGB, pero NO en imágenes con formato de color como la que parece estar usando.
image = imread(''peppers.png'');
figure(1), clf, hold on
subplot(1,2,1)
imshow(image);
degree = 45;
switch mod(degree, 360)
% Special cases
case 0
imagerot = image;
case 90
imagerot = rot90(image);
case 180
imagerot = image(end:-1:1, end:-1:1);
case 270
imagerot = rot90(image(end:-1:1, end:-1:1));
% General rotations
otherwise
% Convert to radians and create transformation matrix
a = degree*pi/180;
R = [+cos(a) +sin(a); -sin(a) +cos(a)];
% Figure out the size of the transformed image
[m,n,p] = size(image);
dest = round( [1 1; 1 n; m 1; m n]*R );
dest = bsxfun(@minus, dest, min(dest)) + 1;
imagerot = zeros([max(dest) p],class(image));
% Map all pixels of the transformed image to the original image
for ii = 1:size(imagerot,1)
for jj = 1:size(imagerot,2)
source = ([ii jj]-dest(1,:))*R.'';
if all(source >= 1) && all(source <= [m n])
% Get all 4 surrounding pixels
C = ceil(source);
F = floor(source);
% Compute the relative areas
A = [...
((C(2)-source(2))*(C(1)-source(1))),...
((source(2)-F(2))*(source(1)-F(1)));
((C(2)-source(2))*(source(1)-F(1))),...
((source(2)-F(2))*(C(1)-source(1)))];
% Extract colors and re-scale them relative to area
cols = bsxfun(@times, A, double(image(F(1):C(1),F(2):C(2),:)));
% Assign
imagerot(ii,jj,:) = sum(sum(cols),2);
end
end
end
end
subplot(1,2,2)
imshow(imagerot);
Salida:
Estoy tratando de rotar una imagen con Matlab sin usar la función de imrotación. De hecho, lo hice utilizando la matriz de transformación. Pero no es lo suficientemente bueno. El problema es que la imagen girada es "deslizante". Déjame que te cuente las imágenes.
Esta es mi imagen que quiero rotar:
Pero cuando lo giro, por ejemplo 45 grados, se convierte en esto:
Estoy preguntando por qué está sucediendo esto. Aquí está mi código, ¿hay algún error matemático o de programación al respecto?
image=torso;
%image padding
[Rows, Cols] = size(image);
Diagonal = sqrt(Rows^2 + Cols^2);
RowPad = ceil(Diagonal - Rows) + 2;
ColPad = ceil(Diagonal - Cols) + 2;
imagepad = zeros(Rows+RowPad, Cols+ColPad);
imagepad(ceil(RowPad/2):(ceil(RowPad/2)+Rows-1),ceil(ColPad/2):(ceil(ColPad/2)+Cols-1)) = image;
degree=45;
%midpoints
midx=ceil((size(imagepad,1)+1)/2);
midy=ceil((size(imagepad,2)+1)/2);
imagerot=zeros(size(imagepad));
%rotation
for i=1:size(imagepad,1)
for j=1:size(imagepad,2)
x=(i-midx)*cos(degree)-(j-midy)*sin(degree);
y=(i-midx)*sin(degree)+(j-midy)*cos(degree);
x=round(x)+midx;
y=round(y)+midy;
if (x>=1 && y>=1)
imagerot(x,y)=imagepad(i,j); % k degrees rotated image
end
end
end
figure,imagesc(imagerot);
colormap(gray(256));
Gira la imagen en color según el ángulo dado por el usuario sin ningún recorte de la imagen en matlab.
La salida de este programa es similar a la salida del comando incorporado "imrotate" .Este programa crea dinámicamente el fondo de acuerdo con el ángulo de entrada dado por el usuario. Al utilizar la matriz de rotación y el cambio de origen, obtenemos una relación entre las coordenadas de la imagen inicial y final. Coordenadas de la imagen inicial y final, ahora mapeamos los valores de intensidad para cada píxel.
img=imread(''img.jpg'');
[rowsi,colsi,z]= size(img);
angle=45;
rads=2*pi*angle/360;
%calculating array dimesions such that rotated image gets fit in it exactly.
% we are using absolute so that we get positve value in any case ie.,any quadrant.
rowsf=ceil(rowsi*abs(cos(rads))+colsi*abs(sin(rads)));
colsf=ceil(rowsi*abs(sin(rads))+colsi*abs(cos(rads)));
% define an array withcalculated dimensionsand fill the array with zeros ie.,black
C=uint8(zeros([rowsf colsf 3 ]));
%calculating center of original and final image
xo=ceil(rowsi/2);
yo=ceil(colsi/2);
midx=ceil((size(C,1))/2);
midy=ceil((size(C,2))/2);
% in this loop we calculate corresponding coordinates of pixel of A
% for each pixel of C, and its intensity will be assigned after checking
% weather it lie in the bound of A (original image)
for i=1:size(C,1)
for j=1:size(C,2)
x= (i-midx)*cos(rads)+(j-midy)*sin(rads);
y= -(i-midx)*sin(rads)+(j-midy)*cos(rads);
x=round(x)+xo;
y=round(y)+yo;
if (x>=1 && y>=1 && x<=size(img,1) && y<=size(img,2) )
C(i,j,:)=img(x,y,:);
end
end
end
imshow(C);
La razón por la que tiene agujeros en su imagen es porque está calculando la ubicación en imagerot
de cada píxel en imagepad
. Necesitas hacer el cálculo al revés. Es decir, para cada píxel en imagerot
interpola en imagepad
. Para hacer esto, solo necesitas aplicar la transformada inversa, que en el caso de una matriz de rotación es solo la transposición de la matriz (solo cambia el signo en cada sin
y traduce al otro lado).
Bucle sobre píxeles en imagerot
:
imagerot=zeros(size(imagepad)); % midx and midy same for both
for i=1:size(imagerot,1)
for j=1:size(imagerot,2)
x= (i-midx)*cos(rads)+(j-midy)*sin(rads);
y=-(i-midx)*sin(rads)+(j-midy)*cos(rads);
x=round(x)+midx;
y=round(y)+midy;
if (x>=1 && y>=1 && x<=size(imagepad,2) && y<=size(imagepad,1))
imagerot(i,j)=imagepad(x,y); % k degrees rotated image
end
end
end
También tenga en cuenta que su midx
y midy
deben calcularse con el size(imagepad,2)
y el size(imagepad,1)
respectivamente, ya que la primera dimensión se refiere al número de filas (altura) y la segunda a la anchura.
NOTA: El mismo enfoque se aplica cuando decide adoptar un esquema de interpolación distinto del vecino más cercano, como en el ejemplo de Rody con interpolación lineal.
EDITAR : Supongo que está utilizando un bucle con fines demostrativos, pero en la práctica no hay necesidad de bucles. Este es un ejemplo de la interpolación del vecino más cercano (lo que está usando), manteniendo la imagen del mismo tamaño, pero puede modificarla para producir una imagen más grande que incluya toda la imagen de origen:
imagepad = imread(''peppers.png'');
[nrows ncols nslices] = size(imagepad);
midx=ceil((ncols+1)/2);
midy=ceil((nrows+1)/2);
Mr = [cos(pi/4) sin(pi/4); -sin(pi/4) cos(pi/4)]; % e.g. 45 degree rotation
% rotate about center
[X Y] = meshgrid(1:ncols,1:nrows);
XYt = [X(:)-midx Y(:)-midy]*Mr;
XYt = bsxfun(@plus,XYt,[midx midy]);
xout = round(XYt(:,1)); yout = round(XYt(:,2)); % nearest neighbor!
outbound = yout<1 | yout>nrows | xout<1 | xout>ncols;
zout=repmat(cat(3,1,2,3),nrows,ncols,1); zout=zout(:);
xout(xout<1) = 1; xout(xout>ncols) = ncols;
yout(yout<1) = 1; yout(yout>nrows) = nrows;
xout = repmat(xout,[3 1]); yout = repmat(yout,[3 1]);
imagerot = imagepad(sub2ind(size(imagepad),yout,xout,zout(:))); % lookup
imagerot = reshape(imagerot,size(imagepad));
imagerot(repmat(outbound,[1 1 3])) = 0; % set background value to [0 0 0] (black)
Para modificar lo anterior a interpolación lineal, calcule los 4 píxeles XYt
a cada coordenada en XYt
y realice una suma ponderada utilizando el producto de componentes fraccionarios como los pesos. Dejaré eso como un ejercicio, ya que solo serviría para inflar mi respuesta más allá del alcance de su pregunta. :)
Mira esto.
Esta es la forma más rápida que puedes hacer.
img = imread(''Koala.jpg'');
theta = pi/10;
rmat = [
cos(theta) sin(theta) 0
-sin(theta) cos(theta) 0
0 0 1];
mx = size(img,2);
my = size(img,1);
corners = [
0 0 1
mx 0 1
0 my 1
mx my 1];
new_c = corners*rmat;
T = maketform(''affine'', rmat); %# represents translation
img2 = imtransform(img, T, ...
''XData'',[min(new_c(:,1)) max(new_c(:,1))],...
''YData'',[min(new_c(:,2)) max(new_c(:,2))]);
subplot(121), imshow(img);
subplot(122), imshow(img2);