基于双线性插值的图像旋转原理及MATLAB实现(非自带函数)

目录

  • 1.图像旋转的原理
    • 1.1.旋转矩阵
    • 1.2.双线性插值
    • 1.3.像素点匹配
  • 2.实现效果与说明

1.图像旋转的原理

1.1.旋转矩阵

旋转一幅图像(假设这幅图像大小是矩形的),当然应该从像素点(pixels)开始,在直角坐标系中,对点x0=[a0b0]x_0=\begin{bmatrix}a_0\\b_0\\ \end{bmatrix}x0=[a0b0]逆时针旋转角度θ\thetaθx1=[a1b1]x_1=\begin{bmatrix}a_1\\b_1\\ \end{bmatrix}x1=[a1b1]的变换公式为
x1=[cosθ−sinθsinθcosθ]x0x_1=\begin{bmatrix}cos\theta & -sin\theta \\ sin\theta & cos\theta\\ \end{bmatrix}x_0x1=[cosθsinθsinθcosθ]x0
那么对图像上的每个点调用这个旋转公式,将旧图像像素点的RGB值搬移到新图像像素点,就可以将图像旋转到任意位置。
但是问题来了,显示屏的像素点是有限的,这意味着显示在显示屏上的像素点坐标必须是整数,旋转过后的图像的每个像素点坐标难免有非整数的情况,那么这种情况下我们怎么处理呢?
我们不妨假设逆时针旋转θ\thetaθ旋转后的图形上所有的像素点都是整点,对于旋转后的图形的每个像素点x1x_1x1,求旋转前图形的对应像素点的坐标x0x_0x0,取ω=−θ\omega=-\thetaω=θ为逆旋转角度,则旋转后的像素点和旋转前的像素点的对应关系为:
x0=[cosω−sinωsinωcosω]x1x_0=\begin{bmatrix}cos\omega & -sin\omega \\ sin\omega & cos\omega\\ \end{bmatrix}x_1x0=[cosωsinωsinωcosω]x1
此时x0x_0x0不一定为整点,x0x_0x0的像素值需要做一定的近似。近似的方法有最近邻插值、双线性插值等等,在这里我们就介绍比较实用且不是很复杂的双线性插值,该插值方法不会产生明显失真现象。
对于像素点的旋转坐标函数编写如下:
坐标旋转变换函数:rot.m

function y=rot(p,angle)
%p=[x,y]为角度制
angle=angle*pi/180;%角度制输入进行计算
y=[cos(angle) -sin(angle);sin(angle) cos(angle)]*p';
end

1.2.双线性插值

对于x和y坐标非整数的非整点xpx_pxp,假设它周围的四个整点坐标分别为x11,x12,x21,x22x_{11},x_{12},x_{21},x_{22}x11,x12,x21,x22(构成一个矩形)。假设第一维度是x坐标,第二维度是y坐标。则x11(1)=x21(1)≤xp(1)≤x12(1)=x22(1)x_{11}(1)=x_{21}(1)≤x_p(1)≤x_{12}(1)=x_{22}(1)x11(1)=x21(1)xp(1)x12(1)=x22(1)
x11(2)=x12(2)≥xp(2)≥x21(2)=x22(2)x_{11}(2)=x_{12}(2)≥x_p(2)≥x_{21}(2)=x_{22}(2)x11(2)=x12(2)xp(2)x21(2)=x22(2)
显然,即使xpx_pxp为整点,仍然存在这样的四个点x11,x12,x21,x22x_{11},x_{12},x_{21},x_{22}x11,x12,x21,x22使得上式成立。
在下图中,P为非整点,存在4个整点Q12,Q11,Q22,Q21Q_{12},Q_{11},Q_{22},Q_{21}Q12,Q11,Q22,Q21将P点包围在其中,设纵向比例系数β=y−y2y1−y2\color{blue}\beta=\frac{y-y_2}{y_1-y_2}β=y1y2yy2,横向比例系数α=x−x1x2−x1\color{blue}\alpha=\frac{x-x_1}{x_2-x_1}α=x2x1xx1颜色函数F(P)F(P)F(P)在四个整点处的值分比为F12,F11,F22,F21F_{12},F_{11},F_{22},F_{21}F12,F11,F22,F21,则P点的函数值
FP=β[(1−α)F11+αF21]+(1−β)[(1−α)F12+αF22]F_P=\beta[(1-\alpha)F_{11}+\alpha F_{21}]+(1-\beta)[(1-\alpha)F_{12}+\alpha F_{22}]FP=β[(1α)F11+αF21]+(1β)[(1α)F12+αF22]写成矩阵的形式即为:
FP=[1−αα][F11F12F21F22][β1−β]F_P=\begin{bmatrix}1-\alpha & \alpha \end{bmatrix}\begin{bmatrix} F_{11} & F_{12} \\[2ex] F_{21} & F_{22} \end{bmatrix}\begin{bmatrix}\beta \\[2ex] 1-\beta \end{bmatrix}FP=[1αα][F11F21F12F22][β1β]
在这里插入图片描述
对于灰度图像,F(P)F(P)F(P)是一维函数,对于RGB图像,F(P)=[FR(P)FG(P)FB(P)]F(P)=\begin{bmatrix}F_R(P) \\F_G(P) \\ F_B(P) \end{bmatrix}F(P)=FR(P)FG(P)FB(P)
由于该公式较为复杂,可以单独编写双线性插值函数,输入为一个任意点坐标,和图像每个点的像素;输出为该点进行双线性插值后的颜色函数值。但需要主要的是,若给采集的4个周围整点,有其中一个超出了图像边界,考虑到图像边界一般为白色,则以白色为替代。检测点是否在画布内只需要条件判断语句就够了。
检测是否在画布内的判断程序:isinrect.m

function y=isinrect(plt,rect)
if plt(1)>=rect(1) && plt(1)<=rect(2) && plt(2)>=rect(3) && plt(2)<=rect(4)y=true;
elsey=false;
end

双线性插值函数:linear_interp.m

function y=linear_interp(p,img)%p为需要双线性插值的点坐标(向量)x=p(1);y=p(2);m=size(img,1);n=size(img,2);x1=floor(x);x2=ceil(x);y1=floor(y);y2=ceil(y);%[x,y]四周的四个整点left=x-x1;%距左边线距离bottom=y-y1;%距底线距离plt=[x1,y2;x2,y2;x1,y2;x2,y2];img_rect=[1,m,1,n];%原图像的矩形框pix_rect=zeros(1,4,3);for t=1:4if isinrect(plt(t,:),img_rect)for color=1:3pix_rect(1,t,color)=img(plt(t,1),plt(t,2),color);endelsepix_rect(1,t,:)=255;%背景色为白色endendpixels=zeros(1,3);%保存该点的三原色的三个像素pix_rect=reshape(pix_rect,2,2,3);for color=1:3pixels(color)=[bottom,1-bottom]*pix_rect(:,:,color)*[1-left;left];%双线性像素插值endy=pixels;
end

1.3.像素点匹配

假设图像的点都是整点的情况下,新图像是一个旋转后的矩形,此时需要给新图像定界使得新图像能够包括在一个旋转角度为0°大矩形中。
在这里插入图片描述
left=max(x1,x2,x3,x4),right=min(x1,x2,x3,x4)left=max(x_1,x_2,x_3,x_4),right=min(x_1,x_2,x_3,x_4)left=max(x1,x2,x3,x4),right=min(x1,x2,x3,x4)
top=max(y1,y2,y3,y4),bottom=min(y1,y2,y3,y4)top=max(y_1,y_2,y_3,y_4),bottom=min(y_1,y_2,y_3,y_4)top=max(y1,y2,y3,y4),bottom=min(y1,y2,y3,y4)

filename='足球.bmp';%文件的完整路径名
img=imread(filename);%导入图像
% subplot(121)
% imshow(img)%展示原图像
m=size(img,1);n=size(img,2);%统计图像的长和宽
plt=[0,0;m,0;m,n;0,n];%四个顶点坐标
for t=1:4plt(t,:)=ceil(rot(plt(t,:),rot_angle));%三个顶点进行旋转坐标变换
end
%新的四个点坐标的x和y边界值
left=min(plt(:,1));right=max(plt(:,1));
bottom=min(plt(:,2));top=max(plt(:,2));
M=right-left;N=top-bottom;%获取新的图像大小
new_img=255*ones(M,N,3);%创建新画布
left=min(plt(:,1));right=max(plt(:,1));
bottom=min(plt(:,2));top=max(plt(:,2));

定界完成后,只需要求出新图像定界后每个像素点对应的原图像像素点坐标,并按照双线性插值的方法取得像素值,对应到新图像点中,即可求出每个新图像点的像素值,旋转步骤即完成。要注意的是,如果双线性插值遇到了原图像界限外的点,为保证程序不出错,可以直接将界限外的点置为0(相当于非常弱的边缘虚化效果),或者直接将最外层边界整点进行最近邻插值(这种分段算法实现会略微麻烦)。主函数文件代码如下:
主函数文件:img_process.m

function img_process(rot_angle)
close all
filename='足球.bmp';%文件的完整路径名
img=imread(filename);%导入图像
figure
imshow(img)%展示原图像
m=size(img,1);n=size(img,2);%统计图像的长和宽
plt=[0,0;m,0;m,n;0,n];%四个顶点坐标
for t=1:4plt(t,:)=ceil(rot(plt(t,:),rot_angle));%三个顶点进行旋转坐标变换
end
%新的四个点坐标的x和y边界值
left=min(plt(:,1));right=max(plt(:,1));
bottom=min(plt(:,2));top=max(plt(:,2));
M=right-left;N=top-bottom;%获取新的图像大小
new_img=255*ones(M,N,3);%创建新画布
for i=1:Mfor j=1:Ninit_plt=rot([i-1+left,j-1+bottom],-rot_angle);%新图像对应原图像的坐标init_plt=init_plt+1;%还原到Matlab坐标系new_img(i,j,:)=linear_interp(init_plt,img);end
end
figure
imshow(uint8(new_img))%展示旋转后的新图像(底色为白色)

2.实现效果与说明

将上述标红的4个M文件放在一个文件夹,并更改MATLAB目录为该文件夹,并在该文件夹添加一张名为“足球.bmp”的位图文件,在命令行输入img_process(30)即可将该图像旋转30°显示,显示效果如下:

原图像新图像(旋转30°)
原图像在这里插入图片描述

本文从原理上用MATLAB代码实现了图像的旋转,如果想直接调用MATLAB的函数,请查看imrotate函数的相关说明:
new_img=imrotate(initial_img,angle,method, ‘crop’)

  • angle:逆时针旋转的角度,是角度值
  • method:该参数为插值方法,其中’bilinear’为双线性插值,可选
  • crop:旋转后增大图像

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

漫画:给女朋友介绍什么是 “元宇宙” ?

什么是更高的自由度呢&#xff1f;或许有人觉得&#xff0c;我们在网络游戏当中&#xff0c;不是也很自由吗&#xff1f;想怎么玩就怎么玩。但是&#xff0c;无论一款网络游戏的元素有多么丰富&#xff0c;游戏当中的角色、任务、职业、道具、场景&#xff0c;都是游戏设计师预…

MyBatis 中为什么不建议使用 where 1=1?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;最近接手了一个老项目&#xff0c;“愉悦的心情”自然无以言表&#xff0c;做开发的朋友都懂&#xff0c;这里就不多说了&am…

【openMV与机器视觉】四旋翼飞行控制背景下的PID控制与摄像头算法简介

文章目录声明1.四旋翼飞行控制简介2.飞行控制算法2.1.接收机PWM生成2.2.PID算法位置PID速度PID3.摄像头算法3.1.图像处理3.2.霍夫曼变换3.3.巡线算法3.3.寻找目标点降落算法声明 \qquad本文的算法在openMV IDE例程的基础上进行原创&#xff0c;在比赛结束后予以发表&#xff1b…

聊聊sql优化的15个小技巧

前言sql优化是一个大家都比较关注的热门话题&#xff0c;无论你在面试&#xff0c;还是工作中&#xff0c;都很有可能会遇到。如果某天你负责的某个线上接口&#xff0c;出现了性能问题&#xff0c;需要做优化。那么你首先想到的很有可能是优化sql语句&#xff0c;因为它的改造…

【MATLAB】Parzen窗与K近邻算法原理与代码详解

文章目录1.非参数估计原理2.Parzen窗2.1.算法原理2.2.Matlab实现与参数探究3.K近邻3.1.算法原理3.2.Matlab实现与参数探究1.非参数估计原理 \qquad已知一个样本的概率分布时&#xff0c;我们只需要对概率分布中的参数进行估计即可得到该样本的概率密度函数。例如已知样本X服从正…

使用 Lambda 表达式实现超强的排序功能

我们在系统开发过程中&#xff0c;对数据排序是很常见的场景。一般来说&#xff0c;我们可以采用两种方式&#xff1a;借助存储系统&#xff08;SQL、NoSQL、NewSQL 都支持&#xff09;的排序功能&#xff0c;查询的结果即是排好序的结果查询结果为无序数据&#xff0c;在内存中…

【mongodb系统学习之四】查看mongodb进程

四、查看mongodb进程&#xff08;可以配合启动和关闭使用&#xff09;&#xff1a; 1&#xff09;、方法一&#xff1a;直接查看mongodb进程是否已经存在&#xff08;用上面的方式启动后&#xff0c;需要另开一个窗口操作&#xff09;&#xff1a;ps –ef|grep mongodb, 如图&a…

【Simulink】粒子群算法(PSO)整定PID参数(附代码和讲解)

目录0.背景1.粒子群算法1.1.算法简介1.2.算法步骤1.3.算法举例2.PID自整定2.1.基于M文件编写的PID参数自整定*2.2.复杂系统的PID自整定&#xff08;基于simulink仿真&#xff09;2.2.1.PSO优化PID的过程详解2.2.2.在PSO优化过程中修改参数价值权重阅读前必看&#xff1a;本代码…

SpringBoot 使用注解实现消息广播功能

背景在开发工作中&#xff0c;会遇到一种场景&#xff0c;做完某一件事情以后&#xff0c;需要广播一些消息或者通知&#xff0c;告诉其他的模块进行一些事件处理&#xff0c;一般来说&#xff0c;可以一个一个发送请求去通知&#xff0c;但是有一种更好的方式&#xff0c;那就…

【Matlab】模式识别——聚类算法集锦

文章目录0.聚类分析简介0.1.简单的聚类样本生成器1.静态聚类算法1.1.最近邻聚类算法1.1.1.算法原理1.1.2.参考代码1.1.3.参数选择及运行结果1.2.最大最小距离法1.2.1.算法原理1.2.2.参考代码1.2.3.参数选择及运行结果2.动态聚类算法2.1.C均值聚类算法2.1.1.算法原理2.1.2.参考代…

【MATLAB】混合粒子群算法原理、代码及详解

目录1.算法1.1.原理1.2.性能比较1.3.步骤2.代码2.1.源码及注释2.2.执行与效果1.算法 1.1.原理 \qquad建议没接触过粒子群算法的朋友先看较为基础的全局粒子群算法原理及介绍&#xff0c;以下博文链接有详细的讲解、代码及其应用举例&#xff1a; 【Simulink】粒子群算法&#…

MVC HtmlHelper用法大全

HtmlHelper用来在视图中呈现 HTML 控件。 以下列表显示了当前可用的一些 HTML 帮助器。 本主题演示所列出的带有星号 (*) 的帮助器。 ActionLink - 链接到操作方法。 BeginForm * - 标记窗体的开头并链接到呈现该窗体的操作方法。 CheckBox * - 呈现复选框。 DropDownList *…

基于 MyBatis 手撸一个分表插件

背景事情是酱紫的&#xff0c;上级leader负责记录信息的业务&#xff0c;每日预估数据量是15万左右&#xff0c;所以引入sharding-jdbc做分表。上级leader完成业务的开发后&#xff0c;走了一波自测&#xff0c;git push后&#xff0c;就忙其他的事情去了。项目的框架是SpringB…

密码学哈希函数_哈希函数在密码学中的应用

密码学哈希函数A Hash Function is a mathematical function that converts a numerical value into another compressed numeric value. The input value for the hash functions can be of arbitrary length, but the output text that it will produce will always be of fi…

C语言图形化界面——含图形、按钮、鼠标、进度条等部件制作(带详细代码、讲解及注释)

目录0.引言1.素材准备2.编程2.1.创建你的界面2.2.创建按钮2.3.鼠标操作2.3.1.单击特效2.3.2.光标感应2.3.3.进度条3.完整代码及效果0.引言 \qquad看了CSDN上很多关于C程序图形化界面的介绍&#xff0c;有的代码繁琐难解&#xff0c;不方便调试修改&#xff1b;有的不够详细。本…

【MATLAB】无人驾驶车辆的模型预测控制技术(精简讲解和代码)【运动学轨迹规划】

文章目录<font color#19C>0.友情链接<font color#19C>1.引言<font color#19C>2.预测模型<font color#19C>3.滚动优化<font color#08CF>3.1.线性化3.2.UrU_rUr​的求取<font color#08CF>3.3.离散化与序列化<font color#08CF>3.4.实现…

顶级Javaer,常用的 14 个类库

作者&#xff1a;小姐姐味道&#xff08;微信公众号ID&#xff1a;xjjdog&#xff09;昨天下载下来Java16尝尝鲜。一看&#xff0c;好家伙&#xff0c;足足有176MB大。即使把jmc和jvisualvm给搞了出去&#xff0c;依然还是这么大&#xff0c;真的是让人震惊不已。但即使JDK足够…

单层神经网络线性回归_单层神经网络| 使用Python的线性代数

单层神经网络线性回归A neural network is a powerful tool often utilized in Machine Learning because neural networks are fundamentally very mathematical. We will use our basics of Linear Algebra and NumPy to understand the foundation of Machine Learning usin…

面试官:说一下 final 和 final 的 4 种用法?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;重要说明&#xff1a;本篇为博主《面试题精选-基础篇》系列中的一篇&#xff0c;查看系列面试文章请关注我。Gitee 开源地址…

面试官:int和Integer有什么区别?为什么要有包装类?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;重要说明&#xff1a;本篇为博主《面试题精选-基础篇》系列中的一篇&#xff0c;查看系列面试文章请关注我。Gitee 开…