您的位置:首页 > 编程语言 > MATLAB

matlab实现彩色图像的平移、旋转、缩放、镜像(双线性插值)

2020-06-04 08:03 1426 查看

matlab双线性插值实现彩色图像的平移、旋转、缩放、镜像

  • 结果
  • 原理概述

    图像的几何变换改变了像素的空间位置,建立一种原图像像素与变换后图像像素之间的映射关系,通过这种映射关系能够实现下面两种计算:
    1.原图像任意像素计算该像素在变换后图像的坐标位置
    2.变换后图像的任意像素在原图像的坐标位置
    对于第一种计算,只要给出原图像上的任意像素坐标,都能通过对应的映射关系获得到该像素在变换后图像的坐标位置。将这种输入图像坐标映射到输出的过程称为“向前映射”。反过来,知道任意变换后图像上的像素坐标,计算其在原图像的像素坐标,将输出图像映射到输入的过程称为“向后映射”。但是,在使用向前映射处理几何变换时却有一些不足,通常会产生两个问题:映射不完全,映射重叠。
    1.映射不完全
    输入图像的像素总数小于输出图像,这样输出图像中的一些像素找不到在原图像中的映射。

    上图只有(0,0),(0,2),(2,0),(2,2)四个坐标根据映射关系在原图像中找到了相对应的像素,其余的12个坐标没有有效值。
    2.映射重叠
    根据映射关系,输入图像的多个像素映射到输出图像的同一个像素上。

    上图左上角的四个像素(0,0),(0,1),(1,0),(1,1)都会映射到输出图像的(0,0)上,那么(0,0)究竟取那个像素值呢?
    要解决上述两个问题可以使用“向后映射”,使用输出图像的坐标反过来推算改坐标对应于原图像中的坐标位置。这样,输出图像的每个像素都可以通过映射关系在原图像找到唯一对应的像素,而不会出现映射不完全和映射重叠。所以,一般使用向后映射来处理图像的几何变换。从上面也可以看出,向前映射之所以会出现问题,主要是由于图像像素的总数发生了变化,也就是图像的大小改变了。在一些图像大小不会发生变化的变换中,向前映射还是很有效的。
    对于数字图像而言,像素的坐标是离散型非负整数,但是在进行变换的过程中有可能产生浮点坐标值。例如,原图像坐标(9,9)在缩小一倍时会变成(4.5,4.5),这显然是一个无效的坐标。插值算法就是用来处理这些浮点坐标的。常见的插值算法有最邻近插值法、双线性插值法,二次立方插值法,三次立方插值法等。
    双线性插值的插值效果比最邻近插值要好很多,相应的计算速度也要慢上不少。双线性插值的主要思想是计算出浮点坐标像素近似值。那么要如何计算浮点坐标的近似值呢。一个浮点坐标必定会被四个整数坐标所包围,将这个四个整数坐标的像素值按照一定的比例混合就可以求出浮点坐标的像素值。混合比例为距离浮点坐标的距离。

    假如我们想得到未知函数f在点P= (x,y) 的值,假设我们已知函数f在Q11 = (x1,y1)、Q12 = (x1,y2),Q21 = (x2,y1) 以及Q22 = (x2,y2) 四个点的值。首先在x方向进行线性插值,得到R1和R2,然后在y方向进行线性插值,得到P.这样就得到所要的结果f(x,y).其中红色点Q11,Q12,Q21,
    Q22为已知的4个像素点.第一步:X方向的线性插值,在Q12,Q22中插入蓝色点R2,Q11,Q21中插入蓝色点R1;第二步 :Y方向的线性插值 ,通过第一步计算出的R1与R2在y方向上插值计算出P点。线性插值的结果与插值的顺序无关。首先进行y方向的插值,然后进行x方向的插值,所得到的结果是一样的。双线性插值的结果与先进行哪个方向的插值无关。如果选择一个坐标系统使得 的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为
    f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy
    在x与y方向上,z值成单调性特性的应用中,此种方法可以做外插运算,即可以求解Q1~Q4所构成的正方形以外的点的值。
    图像的平移变换就是将图像所有的像素坐标分别加上指定的水平偏移量和垂直偏移量。
    设dx为水平偏移量,dy为垂直偏移量,(x0,y0)为原图像坐标,(x,y)为变换后图像坐标,则平移变换的坐标映射为

    这是向前映射,即将原图像的坐标映射到变换后的图像上。
    其逆变换为

    向后映射,即将变换后的图像坐标映射到原图像上。在图像的几何变换中,一般使用向后映射。
    图像的镜像变换分为两种:水平镜像和垂直镜像。水平镜像以图像垂直中线为轴,将图像的像素进行对换,也就是将图像的左半部和右半部对调。垂直镜像则是以图像的水平中线为轴,将图像的上半部分和下班部分对调。
    设图像的宽度为width,长度为height。(x,y)为变换后的坐标,(x0,y0)为原图像的坐标

    图像的缩放主要用于改变图像的大小,缩放后图像的图像的宽度和高度会发生变化。水平缩放系数,控制图像宽度的缩放,其值为1,则图像的宽度不变;垂直缩放系数控制图像高度的缩放,其值为1,则图像的高度不变。如果水平缩放系数和垂直缩放系数不相等,那么缩放后图像的宽度和高度的比例会发生变化,会使图像变形。要保持图像宽度和高度的比例不发生变化,就需要水平缩放系数和垂直缩放系数相等。
    设水平缩放系数为sx,垂直缩放系数为sy,(x0,y0)为缩放前坐标,(x,y)为缩放后坐标,其缩放的坐标映射关系:

    这是向前映射,在缩放的过程改变了图像的大小,使用向前映射会出现映射重叠和映射不完全的问题,所以这里更关心的是向后映射,也就是输出图像通过向后映射关系找到其在原图像中对应的像素。
    向后映射关系:

    图像的旋转就是让图像按照某一点旋转指定的角度。图像旋转后不会变形,但是其垂直对称抽和水平对称轴都会发生改变,旋转后图像的坐标和原图像坐标之间的关系已不能通过简单的加减乘法得到,而需要通过一系列的复杂运算。而且图像在旋转后其宽度和高度都会发生变化,其坐标原点会发生变化。
    图像所用的坐标系不是常用的笛卡尔,其左上角是其坐标原点,X轴沿着水平方向向右,Y轴沿着竖直方向向下。而在旋转的过程一般使用旋转中心为坐标原点的笛卡尔坐标系,所以图像旋转的第一步就是坐标系的变换。设旋转中心为(x0,y0),(x’,y’)是旋转后的坐标,(x,y)是旋转后的坐标,则坐标变换如下:

    在最终的实现中,常用到的是有缩放后的图像通过映射关系找到其坐标在原图像中的相应位置,这就需要上述映射的逆变换


    由于在旋转的时候是以旋转中心为坐标原点的,旋转结束后还需要将坐标原点移到图像左上角,也就是还要进行一次变换。这里需要注意的是,旋转中心的坐标(x0,y0)实在以原图像的左上角为坐标原点的坐标系中得到,而在旋转后由于图像的宽和高发生了变化,也就导致了旋转后图像的坐标原点和旋转前的发生了变换。

    上边两图,可以清晰的看到,旋转前后图像的左上角,也就是坐标原点发生了变换。
    在求图像旋转后左上角的坐标前,先来看看旋转后图像的宽和高。从上图可以看出,旋转后图像的宽和高与原图像的四个角旋转后的位置有关。
    设top为旋转后最高点的纵坐标,down为旋转后最低点的纵坐标,left为旋转后最左边点的横坐标,right为旋转后最右边点的横坐标。
    旋转后的宽和高为newWidth,newHeight,则可得到下面的关系:

    也就很容易的得出旋转后图像左上角坐标(left,top)(以旋转中心为原点的坐标系)故在旋转完成后要将坐标系转换为以图像的左上角为坐标原点,可由下面变换关系得到:


    综合以上,也就是说原图像的像素坐标要经过三次的坐标变换:
    1.将坐标原点由图像的左上角变换到旋转中心
    2.以旋转中心为原点,图像旋转角度a
    3.旋转结束后,将坐标原点变换到旋转后图像的左上角
    可以得到下面的旋转公式:(x’,y’)旋转后的坐标,(x,y)原坐标,(x0,y0)旋转中心,a旋转的角度(顺时针)

    这种由输入图像通过映射得到输出图像的坐标,是向前映射。常用的向后映射是其逆运算

    代码

    平移

    function res = translation(x, y, image)
    res = im2uint8(zeros(size(image)));
    [rows,cols,v] = size(image); % 图像行列数
    res1 = im2uint8(zeros([rows,cols]));
    res2 = im2uint8(zeros([rows,cols]));
    res3 = im2uint8(zeros([rows,cols]));
    temp1 = image(:, :, 1);
    temp2 = image(:, :, 2);
    temp3 = image(:, :, 3);
    translation_matrix = [1 0 x; 0 1 y; 0 0 1];
    for i = 1:rows
    for j = 1:cols
    temp = [i; j; 1];
    temp = translation_matrix * temp;
    m = temp(1, 1);
    n = temp(2, 1);
    if (m <= rows) && (n <= cols) && (m >= 1) && (n >= 1)
    res1(m,n) = temp1(i,j);
    res2(m,n) = temp2(i,j);
    res3(m,n) = temp3(i,j);
    end
    end
    end
    res(:, :, 1) = res1;
    res(:, :, 2) = res2;
    res(:, :, 3) = res3;
    res = uint8(res);

    镜像

    function res = mirror(image)
    res = im2uint8(zeros(size(image)));
    [rows,cols,n] = size(image); % 图像行列数
    res1 = im2uint8(zeros([rows,cols]));
    res2 = im2uint8(zeros([rows,cols]));
    res3 = im2uint8(zeros([rows,cols]));
    temp1 = image(:, :, 1);
    temp2 = image(:, :, 2);
    temp3 = image(:, :, 3);
    for i = 1:rows
    for j = 1:cols
    % 左右镜像
    % res1(i,cols-j+1) = temp1(i,j);
    % res2(i,cols-j+1) = temp2(i,j);
    % res3(i,cols-j+1) = temp3(i,j);
    % 上下镜像
    res1(rows-i+1,j) = temp1(i,j);
    res2(rows-i+1,j) = temp2(i,j);
    res3(rows-i+1,j) = temp3(i,j);
    end
    end
    res(:, :, 1) = res1;
    res(:, :, 2) = res2;
    res(:, :, 3) = res3;
    res = uint8(res);

    缩放

    function res = zoom(x, y, image)
    [rows,cols,v] = size(image); % 图像行列数
    res = zeros([rows * x,cols * y,v]);
    res1 = zeros([rows * x,cols * y]);
    res2 = zeros([rows * x,cols * y]);
    res3 = zeros([rows * x,cols * y]);
    temp1 = im2uint8(image(:, :, 1));
    temp2 = im2uint8(image(:, :, 2));
    temp3 = im2uint8(image(:, :, 3));
    for i = 1:rows * x
    for j = 1:cols * y
    m = floor(i / x);
    n = floor(j / y);
    u = (i / x) - m;
    v = (j / y) - n;
    if (m <= rows) && (n <= cols) && (m >= 1) && (n >= 1)
    res1(i,j) = temp1(floor(m), floor(n)) * (1-u) * (1-v) + temp1(floor(m), ceil(n)) * (1-u) * v + temp1(ceil(m), floor(n)) * u * (1-v) + temp1(ceil(m), ceil(n)) * u * v;
    res2(i,j) = temp2(floor(m), floor(n)) * (1-u) * (1-v) + temp2(floor(m), ceil(n)) * (1-u) * v + temp2(ceil(m), floor(n)) * u * (1-v) + temp2(ceil(m), ceil(n)) * u * v;
    res3(i,j) = temp3(floor(m), floor(n)) * (1-u) * (1-v) + temp3(floor(m), ceil(n)) * (1-u) * v + temp3(ceil(m), floor(n)) * u * (1-v) + temp3(ceil(m), ceil(n)) * u * v;
    end
    end
    end
    res(:, :, 1) = res1;
    res(:, :, 2) = res2;
    res(:, :, 3) = res3;
    res = uint8(res);

    旋转

    function res = rotation(angle, image)
    [rows,cols,v] = size(image); % 图像行列数
    temp1 = im2uint8(image(:, :, 1));
    temp2 = im2uint8(image(:, :, 2));
    temp3 = im2uint8(image(:, :, 3));
    
    theta=(angle / 180) * pi;
    rotation_matrix=[cos(theta) -sin(theta) 0; sin(theta) cos(theta) 0; 0 0 1];
    up_left=[1 1 1]*rotation_matrix;
    up_right=[1 cols 1]*rotation_matrix;
    down_left=[rows 1 1]*rotation_matrix;
    down_right=[rows cols 1]*rotation_matrix;
    height=round(max([abs(up_left(1)-down_right(1))+0.5 abs(up_right(1)-down_left(1))+0.5]));     %变换后图像的高度
    width=round(max([abs(up_left(2)-down_right(2))+0.5 abs(up_right(2)-down_left(2))+0.5]));      %变换后图像的宽度
    res = zeros([height,width,v]);
    res1 = zeros([height,width]);
    res2 = zeros([height,width]);
    res3 = zeros([height,width]);
    delta_y=abs(min([up_left(1) up_right(1) down_left(1) down_right(1)]));
    delta_x=abs(min([up_left(2) up_right(2) down_left(2) down_right(2)]));
    for i=1-delta_y:height-delta_y
    for j=1-delta_x:width-delta_x
    point = [i j 1]/rotation_matrix;
    m = point(1);
    n = point(2);
    u=m-floor(m);
    v=n-floor(n);
    if (m <= rows) && (n <= cols) && (m >= 1) && (n >= 1)
    res1(i+delta_y,j+delta_x) = temp1(floor(m), floor(n)) * (1-u) * (1-v) + temp1(floor(m), ceil(n)) * (1-u) * v + temp1(ceil(m), floor(n)) * u * (1-v) + temp1(ceil(m), ceil(n)) * u * v;
    res2(i+delta_y,j+delta_x) = temp2(floor(m), floor(n)) * (1-u) * (1-v) + temp2(floor(m), ceil(n)) * (1-u) * v + temp2(ceil(m), floor(n)) * u * (1-v) + temp2(ceil(m), ceil(n)) * u * v;
    res3(i+delta_y,j+delta_x) = temp3(floor(m), floor(n)) * (1-u) * (1-v) + temp3(floor(m), ceil(n)) * (1-u) * v + temp3(ceil(m), floor(n)) * u * (1-v) + temp3(ceil(m), ceil(n)) * u * v;
    end
    end
    end
    res(:, :, 1) = res1;
    res(:, :, 2) = res2;
    res(:, :, 3) = res3;
    res = uint8(res);

    结果

    原图

    平移(向X正方向、Y正方向50个距离单位)

    镜像(左右、上下)


    缩放(查看分辨率可知是否成功)

    旋转(45°)

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: