zoukankan      html  css  js  c++  java
  • 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开辟新矩阵,使得旋转后的图像不能完整显示
  • 相关阅读:
    HTML5-拖拽
    POJ1182食物链(并查集)
    欧拉函数之HDU1286找新朋友
    Another kind of Fibonacce(矩阵快速幂,HDU3306)
    我的第一道java_A+B
    bestcoder#33 1002 快速幂取余+模拟乘,组合数学
    快速幂模版
    bestcoder#33 1001 高精度模拟
    poj2446_二分图
    poj3984_bfs+回溯路径
  • 原文地址:https://www.cnblogs.com/Vicky1361/p/13917902.html
Copyright © 2011-2022 走看看