【问题标题】:Image rotation by Matlab without using imrotateMatlab的图像旋转而不使用imrotate
【发布时间】:2013-11-10 03:59:15
【问题描述】:

我正在尝试使用 Matlab 旋转图像而不使用 imrotate 函数。我其实是用变换矩阵做的。但是还不够好。问题是,旋转后的图像是“滑动”的。我用图片告诉你。

这是我要旋转的图像:

但是当我旋转它时,例如 45 度,它变成了这样:

我在问为什么会这样。这是我的代码,是否有任何数学或编程错误?

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));

【问题讨论】:

  • 你试过用弧度代替度数吗?
  • 其实我做了。但什么都没有改变。旋转后的图片是对的,只是它的坐标。
  • 正如@Junuxx 指出的那样,cossin 使用弧度,而不是度数。如果要使用度数,则应使用cosdsind
  • 谢谢,但我也试过了。还是一样。我的方程式有数学错误吗?
  • @Moondra 我想将额外的 1 左 1 右,1 上 1 下填充到图像中。如果我没记错的话,你不必使用它。

标签: matlab image-processing interpolation


【解决方案1】:

看看这个。

这是您可以做到的最快方式。

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);

【讨论】:

  • 嗯,重点是在没有转换函数的情况下学习和执行此操作,无论是imtransform 还是imrotate。但是,是的,这就是你真正做到这一点的方式,所以 +1 来做出贡献。
  • 这使用了图像处理工具箱。关键是在没有它的情况下执行此操作。这个答案也被弃用,因为 maketformimtransform 不再推荐作为执行此操作的官方功能。 affine2dimwarp 现在是。
【解决方案2】:

根据用户给定的角度旋转彩色图像,无需在matlab中裁剪图像。

该程序的输出类似于内置命令“imrotate”的输出。该程序根据用户输入的角度动态创建背景。通过使用旋转矩阵和原点移动,我们得到初始和最终图像坐标之间的关系。使用初始和最终图像坐标之间的关系,我们现在映射每个像素的强度值。

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);

【讨论】:

    【解决方案3】:

    图像中有孔的原因是因为您正在计算imagepad 中每个像素在imagerot 中的位置。您需要以相反的方式进行计算。也就是说,对于imagerot 中的每个像素,在imagepad 中进行插值。为此,您只需应用逆变换,在旋转矩阵的情况下,它只是矩阵的转置(只需更改每个 sin 上的符号并以另一种方式进行转换)。

    循环遍历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
    

    另请注意,您的midxmidy 需要分别使用size(imagepad,2)size(imagepad,1) 计算,因为第一个维度是指行数(高度),第二个是宽度。

    注意:当您决定采用最近邻以外的插值方案时,同样的方法也适用,如 Rody 的线性插值示例。

    编辑:我假设您出于演示目的使用循环,但实际上不需要循环。这是最近邻插值的示例(您正在使用的),保持相同大小的图像,但您可以修改它以生成包含整个源图像的更大图像:

    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)
    

    要将上述修改为线性插值,请计算XYt 中每个坐标的 4 个相邻像素,并使用小数分量乘积作为权重进行加权求和。我将把它留作练习,因为它只会使我的答案超出你的问题范围。 :)

    【讨论】:

    • 谢谢,这确实有效。所以我试图找到错误的(x,y)
    • 我可以再问一件事吗?找到x和y后,为什么要加上midx,midy?我被这个轮换的数学困住了
    • @Zapdos - 要围绕图像的中心旋转,您必须减去质心,变换,然后将其重新添加。
    【解决方案4】:

    您使用的方法(通过采样旋转)是最快和最简单的,但也是最不准确的。

    按区域映射旋转,如下所示(this 是一个很好的参考),在保留颜色方面要好得多。

    但是:请注意,这仅适用于灰度/RGB 图像,而不适用于您似乎正在使用的彩色映射图像。

    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);
    

    输出:

    【讨论】:

    • 处理特殊情况的好主意。请注意,rot90(A,K) 将一次执行 K 90 次旋转,使用与您相同的 180 次旋转方法,然后转置和翻转 270 次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多