小白学习图像处理3——图像旋转原理

一、图像旋转的原理

  图像的旋转类似坐标平面中XOY点的旋转,如下图,点P以坐标原点O为旋转中心,逆时针旋转角度 β 后得到点Q:
在这里插入图片描述
  设P、Q点的坐标分别为 (x, y) 和 (x’, y’),假设P点离坐标原点的距离为D,则通过三角函数有:

x ′ = D c o s ( α + β ) = D ( c o s α c o s β − s i n α s i n β ) = x c o s β − y s i n β x' = D cos(\alpha+\beta)=D(cos\alpha cos\beta - sin\alpha sin\beta) = xcos\beta - ysin\beta x=Dcos(α+β)=D(cosαcosβsinαsinβ)=xcosβysinβ
y ′ = D s i n ( α + β ) = D ( c o s α s i n β + s i n α c o s β ) = x s i n β + y c o s β y' = D sin(\alpha+\beta)=D(cos\alpha sin\beta + sin\alpha cos\beta) = xsin\beta + ycos\beta y=Dsin(α+β)=D(cosαsinβ+sinαcosβ)=xsinβ+ycosβ

  在数字图像中,由于图像是用二维数组存储的,因此上面的公式可以转化为矩阵运算:

R = [ c o s β s i n β 0 − s i n β c o s β 0 0 0 1 ] R= \begin{bmatrix} cos\beta & sin\beta & 0 \\ -sin\beta & cos\beta & 0\\ 0 & 0 & 1 \end{bmatrix} R=cosβsinβ0sinβcosβ0001

[ x ′ y ′ 1 ] = [ x y 1 ] ∗ R \begin{bmatrix} x' & y' & 1 \end{bmatrix} = \begin{bmatrix} x & y & 1 \end{bmatrix}*R [xy1]=[xy1]R



二、使用matlab实现

1、思路

步骤

  1. 构建新的矩阵存储旋转得到的图像
  2. 选择旋转中心
  3. 计算原图像每一个像素点经旋转得到的坐标
  4. 将原图像的像素点值映射到新图像中

问题1:如何确定像素点旋转后的坐标:假设原坐标为P: (x, y),旋转中心为C: (cx, cy),新坐标为Q: (x’, y’),则

C = [cx, cy];
R = [cos(theta) sin(theta); -sin(theta) cos(theta)];
Q = round(R * (P - C) + C);

问题2:如何确定旋转后得到的图像的大小(可以存放下整个旋转后图像的矩形框按大小):
思路:计算原图像四个角上的像素点旋转后的位置,计算行列的覆盖范围:

nw = round(([0, 0]-C)*R + C);
ne = round(([0, width]-C)*R + C);
sw = round(([height, 0]-C)*R + C);
se = round(([height, width]-C)*R + C);
h = max([nw(1), ne(1), sw(1), se(1)]) - min([nw(1), ne(1), sw(1), se(1)]);
w = max([nw(2), ne(2), sw(2), se(2)]) - min([nw(2), ne(2), sw(2), se(2)]);

2、实现代码

根据上述分析,代码如下:

img = imread('lena_color_512.tif');
[height, width,  color] =  size(img);

theta = 1/3*pi;
C = round([height/2, width/2]);     % 原图像中心
R = [cos(theta) sin(theta); -sin(theta) cos(theta)];

% 计算新图像大小
nw = round(([0, 0]-C)*R + C);
ne = round(([0, width]-C)*R + C);
sw = round(([height, 0]-C)*R + C);
se = round(([height, width]-C)*R + C);
h = max([nw(1), ne(1), sw(1), se(1)]) - min([nw(1), ne(1), sw(1), se(1)]);
w = max([nw(2), ne(2), sw(2), se(2)]) - min([nw(2), ne(2), sw(2), se(2)]);

target = zeros(h, w, 3, 'uint8') + 255;
c = round([h/2, w/2]);      % 新图像中心

% 旋转
for x = 1 : height
    for y = 1 : width
        P = [x, y];
        Q = round((P-C)*R + c);
        if (Q(1)>0 && Q(1)<=h) && (Q(2)>0 && Q(2)<=w)   % 越界判断
            target(Q(1), Q(2), :) = img(x, y, :);
        end
    end
end
imshow(target)

得到的结果和我们预料的有些不太一样,有很多小白点,主要原因是根据原图像坐标旋转计算得到的新坐标经过四舍五入后可能一样,导致一些坐标点未赋值,出现白点
在这里插入图片描述


三、优化

1、思路

  由于小白点是像素点未赋值造成的,我们可以遍历新图像的所有像素点,通过逆向寻找原图像对应像素点坐标,从而实现对所有像素点赋值。
问题1:如何根据新图像的坐标点找到原图中对应的坐标点
思路:考虑逆矩阵,从原图到旋转后的图像使用的是变换R,则根据新图像的坐标找到原图像对应坐标可以用R的逆矩阵

R = inv(R);	% 求逆
% 对新图像的坐标 Q(x, y),求原图像坐标P
for x = 1 : h
    for y = 1 : w
        Q = [x, y];
        % 根据目标像素点计算原图像像素点
        P = round((Q-c)*R + C);
        if (P(1)>0 && P(1)<=height) && (P(2)>0 && P(2)<=width)   % 越界判断
            target(x, y, :) = img(P(1), P(2), :);
        end
    end
end

2、代码实现

img = imread('lena_color_512.tif');
[height, width,  color] =  size(img);

theta = 1/4*pi;
C = round([height/2, width/2]);     % 原图像中心
R = [cos(theta) sin(theta); -sin(theta) cos(theta)];
R = inv(R);     % 逆矩阵

% 原图像四个角旋转后的坐标
nw = round(([0, 0]-C)*R + C);
ne = round(([0, width]-C)*R + C);
sw = round(([height, 0]-C)*R + C);
se = round(([height, width]-C)*R + C);

% 新图像
h = max([nw(1), ne(1), sw(1), se(1)]) - min([nw(1), ne(1), sw(1), se(1)]);
w = max([nw(2), ne(2), sw(2), se(2)]) - min([nw(2), ne(2), sw(2), se(2)]);
target = zeros(h, w, 3, 'uint8') + 255;
c = round([h/2, w/2]);      % 新图像中心

for x = 1 : h
    for y = 1 : w
        Q = [x, y];
        % 根据目标像素点计算原图像像素点
        P = round((Q-c)*R + C);
        if (P(1)>0 && P(1)<=height) && (P(2)>0 && P(2)<=width)   % 越界判断
            target(x, y, :) = img(P(1), P(2), :);
        end
    end
end
imshow(target)

结果很棒!
在这里插入图片描述


3、使用双线性插值

  使用双线性插值是图像过度更加平滑,原来程序的for循环中,是通过 round 函数四舍五入得到原图像坐标,现在使用双线性插值(双线性插值的原理可以参考:图像插值
  我们修改for循环的内容:

for x = 1 : h
    for y = 1 : w
        Q = [x, y];
        % 使用双线性插值
        P = (Q-c)*R + C;
        p1 = [ceil(P(1)), ceil(P(2))];
        p2 = [ceil(P(1)), ceil(P(2))+1];
        p3 = [ceil(P(1))+1, ceil(P(2))];
        p4 = [ceil(P(1))+1, ceil(P(2))];
        dx = ceil(P(1)) - P(1);
        dy = ceil(P(2)) - P(2);
        if (P(1)>=1 && P(1)<height-1) && (P(2)>=0 && P(2)<width-1)   % 越界判断
            target(x, y, :) = (1-dx)*(1-dy)*img(p1(1), p1(2), :) + (1-dx)*dy*img(p3(1), p3(2), :)...
                + dx*(1-dy)*img(p2(1), p2(2), :) + dx*dy*img(p4(1), p4(2), :);
        end
    end
end

在这里插入图片描述


四、matlab函数实现图像旋转

  其实,matlab有自带的图像旋转函数 imrotate(会不会觉得前面全部白学了,hhh),举个例子:

1、imrotate函数

%% imrotate
img=imread('lena_color_512.tif');
figure
imshow(img)
figure
% 对I旋转逆时针30°,使用最邻近插值(也可以用bilinear)
imshow(imrotate(img, 30, 'nearest'))

2、imtransform函数

%% imtransform
I = imread('lena_color_512.tif');
theta = -pi/6;
T = [cos(theta) sin(theta) 0; -sin(theta) cos(theta) 0; 0 0 1];	% 构造旋转变换矩阵
tform = maketform('affine',T);	% 生成tform结构体
J = imtransform(I,tform);	% 调用tform进行旋转
imshow(J)

这两个函数执行结果都是一样的:在这里插入图片描述


3、图像块的旋转

拓展 :我们使用blockproc函数实现对图像块的操作,blockproc使用方法如下:

% A 代表图像, [m, n]代表块的大小, fun是函数句柄,表示对每个块的处理函数
B = blockproc(A,[m n],fun);
% processes the image A by applying the function fun to each distinct block of size [m n] and concatenating the results into the output matrix, B.

拓展 :函数句柄相当于C++里面的指针,可以自定义函数句柄:

add = @(a, b) a+b;
class(add)  % function_handle
add(2, 9)	% 相当于 a+b

实现图像块旋转的代码很简洁:

img = imread('lena_color_512.tif');
img = im2double(img);

fun = @(block_struct)...	% 换行符
    imrotate(block_struct.data, 30);	
img1 = blockproc(img, [64, 64], fun);
figure, imshow(img1)

效果如下:
在这里插入图片描述


  以上就是全部的内容啦,介绍了旋转图像的原理和matlab的imrotate函数的使用,通过类比,我们可以知道一些其他图像空间变换的原理,比如平移、放大、缩小、水平/垂直偏移等…

完结 cheers 🍻~

  • 24
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
数字图像处理是一门很广泛的学科,学习它需要一定的基础知识和实践经验。以下是一些建议来帮助你学习数字图像处理: 1. 学习基础知识:开始之前,了解数字图像的基础知识是很重要的。学习图像的像素表示、色彩模型、图像采集和处理等基本概念。 2. 学习算法和技术:了解数字图像处理中常用的算法和技术,如滤波、边缘检测、图像增强、图像分割等。掌握这些算法和技术可以帮助你理解和解决实际问题。 3. 学习编程技能:数字图像处理通常需要编程来实现算法和处理图像。选择一种编程语言,如Python或MATLAB,并学习如何使用它们来进行图像处理。 4. 实践项目:通过实践项目来巩固所学的知识。尝试处理不同类型的图像,并应用所学的算法和技术。这样可以帮助你理解概念,并提高你的实践能力。 5. 学习相关工具:数字图像处理领域有许多常用的工具和库,如OpenCV、PIL等。学习如何使用这些工具可以提高你的效率和准确性。 6. 阅读相关文献和教材:数字图像处理领域有很多经典的文献和教材,阅读它们可以帮助你深入理解概念和算法。可以参考一些经典的教材,如《数字图像处理》(Digital Image Processing)。 7. 参与学习社区:加入数字图像处理学习社区,参与讨论和交流。这样可以与其他学习者和专业人士互相学习和分享经验。 记住,数字图像处理是一个不断发展和演进的领域,持续学习和实践是提高自己的关键。祝你学习顺利!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值