Matlab实现imrotate函数功能

算法分析

  1. 开辟新矩阵存放旋转后的图像。计算公式如下,H为原图像行,W原图像列,a为旋转角度,a是钝角时,三角函数需要加上绝对值
DH = H * abs(cos(a)) + W * abs(sin(a));  
DW = H * abs(sin(a)) + W * abs(cos(a));
  1. 计算旋转后的坐标(旋转方向为逆时针)。利用原坐标点与旋转矩阵相乘,公式如下,x,y为原坐标,a为旋转角度,x',y'为旋转后的坐标

  2. 利用近邻插值给旋转后的图像赋上灰度值。由于是根据旋转后的新矩阵坐标映射回原矩阵中的坐标求其灰度值,所以对旋转矩阵求逆矩阵R,原像素位置记为src,中心点记为center1,旋转后像素位置记为dst,中心点记为center2,近邻插值(四舍五入取近似值),整理为以下公式:

                                                       src = round(R * (dst - center2) + center1)
    

若是彩色图则每个通道都如上赋值

双线性插值:其中i,j为当前点的坐标,u为i坐标的偏移量,v为j坐标的偏移量

                                        f(i+u,j+v) = (1-u)(1-v)f(i,j)+u(1-v)f(i+1,j)+(1-u)vf(i,j+1)+ uvf(i+1,j+1)

近邻插值伪代码

function outputimg = myimrotate(A,angle)
% 利用近邻插值法将图像旋转
% 输入:A是读入的图像矩阵,angle是旋转角度(0-360),angle取正为逆时针旋转,取负为顺时针旋转
% 输出:outputimg是输出的图像矩阵

a = 旋转角度/180 * pi 
R = 旋转矩阵
R = 求逆矩阵

[H,W,CH] = 图像的长、宽、通道
%当旋转角度为钝角(顺时针旋转)时加上绝对值
DH = 根据步骤1的公式求出新矩阵的行
DW = 根据步骤1的公式求出新矩阵的行
outputimg = 按照DH和DW新开辟一个矩阵
center1 = 原图像中心坐标
center2 = 新矩阵中心坐标
遍历新矩阵
          dst = 新矩阵中当前点的坐标
          src = 根据步骤3的公式求得当前点对应在原图上的点的坐标
          如果src的坐标点在原图上没有越界)
             outputimg(i,j,:) = 将各个通道对应点在原图的像素值赋给新矩阵
将outputimg类型转换为uint8便于显示图像;
end

双线性插值伪代码

function outputimg = myimrotate_bilinear(A,angle)
% 利用双线性插值法将图像旋转
% A是读入的图像矩阵,angle是旋转角度(0-360),angle取正为逆时针旋转,取负为顺时针旋转
% outputimg是输出的图像矩阵

a = 旋转角度/180 * pi 
R = 旋转矩阵
R = 逆矩阵

[H,W,CH] = 图像的长、宽、通道
%当旋转角度为钝角(顺时针旋转)时加上绝对值
DH = 根据步骤1的公式求出新矩阵的行
DW = 根据步骤1的公式求出新矩阵的行
outputimg = 按照DH和DW新开辟一个矩阵
center1 = 原图像中心坐标
center2 = 新矩阵中心坐标

遍历新矩阵
          dst = 新矩阵中的当前点
          src = 根据步骤3的公式求得当前点对应在原图上的点的坐标(行、列)
          %双线性插值
          a = 对求得的src向下取整
          offset = 计算的src的偏移量
          u = i坐标(行)的偏移量
          v = j坐标(列)的偏移量
          i = 当前点向下取整之后行坐标
          j = 当前点向下取整之后列坐标
          如果i,j,并且(i+1)、(j+1)没有越界
             outputimg(di,dj,:) = 将各个通道对应点根据步骤4公式所求得的在原图上的像素值赋给新矩阵
将outputimg类型转换为uint8便于显示图像
end

近邻插值代码

function outputimg = myimrotate_neighbor(A,angle)
% 利用近邻插值法将图像旋转
% A是读入的图像矩阵,angle是旋转角度
% outputimg是输出的图像矩阵

%角度转换,求旋转矩阵的逆矩阵
a = angle / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)]; %旋转矩阵
R = R'; %求逆矩阵

%根据原图矩阵生成输出图像所需画布矩阵的大小
[H,W,CH] = size(A);
DH = ceil(H * abs(cos(a)) + W * abs(sin(a)));  %当顺时针旋转时加上绝对值
DW = ceil(H * abs(sin(a)) + W * abs(cos(a)));
outputimg = zeros(DH,DW,CH);
center1 = [H;W] / 2;
center2 = [DH;DW] / 2;

for i = 1:DH
       for j = 1:DW
          dst = [i; j];
          %利用的向量的旋转原理,再与旋转矩阵相乘
          src = round(R * (dst - center2) + center1); %四舍五入近邻插值
          % 逆向进行像素查找
          if (src(1) >= 1 && src(1) <= H && src(2) >= 1 && src(2) <= W)
             outputimg(i,j,:) = A(src(1), src(2),:); 
          end
       end
end
outputimg = uint8(outputimg);
end

实验结果

%调用示例:
A = imread('cameraman.tif');
B = myimrotate_neighbor(A,30);
subplot(1,2,1),imshow(A),title('原图');
subplot(1,2,2),imshow(B),title('旋转30°的图像');

灰度图逆时针30°旋转:

彩色图顺时针30°旋转(等同于逆时针旋转330°):

双线性插值代码

function outputimg = myimrotate_bilinear(A,angle)
% 利用双线性插值法将图像旋转
% A是读入的图像矩阵,angle是旋转角度
% outputimg是输出的图像矩阵


%角度转换,求旋转矩阵的逆矩阵
a = angle / 180 * pi;
R = [cos(a), -sin(a); sin(a), cos(a)];
R = R'; 

%根据原图矩阵生成输出图像所需画布矩阵的大小
[H,W,CH] = size(A);
DH = floor(H * cos(a) + W * sin(a));  %向上取整
DW = floor(H * sin(a) + W * cos(a));
outputimg = zeros(DH,DW,CH);
center1 = [H;W] / 2;
center2 = [DH;DW] / 2;

for di = 1:DH
       for dj = 1:DW
          dst = [di; dj];
          %利用的向量的旋转原理,再与旋转矩阵相乘
          src = (R * (dst - center2) + center1); 
          %双线性插值
          a = floor(src); %向下取整
          offset = src - a;  %计算的偏移量
          u = offset(1);  %x的偏移量
          v = offset(2);  %y的偏移量
          i = a(1);
          j = a(2);
          % 逆向进行像素查找
          if (src(1) >= 1 && src(1) <= H - 1 && src(2) >= 1 && src(2) <= W - 1)
             outputimg(di,dj,:) = (1-u)*(1-v)*A(i, j, :) + (1 - u) * v * A(i, j + 1, :) + u * (1 - v) * A(i + 1, j, :) + u * v * A(i + 1, j + 1, :); 
          end
       end
end
outputimg = uint8(outputimg);
end
% 调用示例:
A = imread('cameraman.tif');
B = myimrotate_bilinear(A,30);
C = myimrotate_neighbor(A,30);
subplot(1,3,1),imshow(A),title('原图');
subplot(1,3,2),imshow(C),title('近邻插值旋转');
subplot(1,3,3),imshow(B),title('双线性插值旋转');

实验结果

实验分析

  • 映射关系的对应,需要根据旋转后的开辟的新矩阵找在原图中的位置,如下图所示,由原图去给新图像赋像素值的时候,有些坐标映射过来是包含小数,在原图上根本找不到,所以得到部分空点(灰度值=0)
  • 新矩阵的开辟,如上图未根据算法分析步骤1开辟新矩阵,使得旋转后的图像不能完整显示
原文地址:https://www.cnblogs.com/Vicky1361/p/13917902.html