数字图像处理(十五)图像旋转

news2025/3/1 14:19:55

文章目录

  • 前言
  • 一、图像旋转算法
    • 1.算法原理
    • 2. 一些需要注意的点
    • 3.举例
    • 4. 均值插值法
  • 二、编程实现
    • 1.C++代码
    • 2.实验结果
  • 参考资料


前言

  图像的旋转是指以图像中的某一点为原点以逆时针或者顺时针方向旋转一定的角度。通常是绕图像的起始点以逆时针进行旋转。


一、图像旋转算法

1.算法原理

  图像旋转计算公式如下: i ′ = i cos ⁡ θ − j sin ⁡ θ i'=i\cos\theta-j\sin \theta i=icosθjsinθ j ′ = i sin ⁡ θ + j cos ⁡ θ j'=i\sin\theta+j\cos\theta j=isinθ+jcosθ
其中, ( i , j ) (i,j) (i,j)是原图像 f ( i , j ) f(i,j) f(i,j)中的像素点坐标; ( i ′ , j ′ ) (i',j') (i,j)是对应像素点 ( i , j ) (i,j) (i,j)经过旋转变换后的图像 g ( i ′ , j ′ ) g(i',j') g(i,j)的坐标。

2. 一些需要注意的点

  1. 旋转只改变图像中像素的位置,不改变像素的值;
  2. 因为图像的坐标值只能是正整数,所以根据上式计算出的新的坐标位置还需要进行处理;
  3. 因为旋转后的图像中间会出现空白点,所以要插值法对空白点进行插值。常用的插值方法有邻近插值法,均值插值法;
  4. 因为旋转后图像的画布大小会发生变化,所以我们还要提前计算新图的画图大小。

3.举例

设原图为 f = [ f 11 f 12 f 13 f 21 f 22 f 23 f 31 f 32 f 33 ] f = \begin{bmatrix} f_{11} & f_{12} & f_{13}\\ f_{21} & f_{22} & f_{23}\\ f_{31} & f_{32} & f_{33}\\ \end{bmatrix} f=f11f21f31f12f22f32f13f23f33
i i i构成的矩阵为: i = [ 1 1 1 2 2 2 3 3 3 ] i= \begin{bmatrix} 1 & 1 & 1\\ 2 & 2 & 2\\ 3 & 3 &3\\ \end{bmatrix} i=123123123
j j j构成的矩阵为: j = [ 1 2 3 1 2 3 1 2 3 ] j= \begin{bmatrix} 1 & 2 & 3\\ 1 & 2 & 3\\ 1 & 2 & 3\\ \end{bmatrix} j=111222333
假设此时要逆时针旋转30度,则根据上面的公式计算 i ′ i' i j ′ j' j
i ′ = i cos ⁡ 30 ° − j sin ⁡ 30 ° i'=i\cos30\degree-j\sin 30\degree i=icos30°jsin30° j ′ = i sin ⁡ 30 ° + j cos ⁡ 30 ° j'=i\sin30\degree+j\cos30\degree j=isin30°+jcos30°
如果要顺时针旋转30度,加个负号就可以了。
计算出的 i ′ i' i构成的矩阵为:
i ′ = [ 0.4 − 0.1 − 0.6 1.2 0.7 0.2 2.1 1.6 1.1 ] i'= \begin{bmatrix} 0.4& -0.1 & -0.6\\ 1.2 & 0.7 & 0.2\\ 2.1 & 1.6 &1.1\\ \end{bmatrix} i=0.41.22.10.10.71.60.60.21.1
此时我们可以看到 i ′ i' i中出现了负数和小数,这在我们编程中是行不通的,所以我们将 i ′ i' i这个矩阵先进行四舍五入。
i ′ = i ′ − min ⁡ ( i ′ ) = i ′ − ( − 0.6 ) = [ 0 0 − 1 1 1 0 2 2 1 ] i'=i'-\min(i')=i'-(-0.6)=\begin{bmatrix} 0 & 0 & -1 \\ 1 & 1 & 0\\ 2 & 2 &1 \\ \end{bmatrix} i=imin(i)=i(0.6)=012012101
又因为坐标没有负数,所以我们将 i ′ i' i中的每个元素加上2变成正整数得
i ′ = [ 2 2 1 3 3 2 4 4 3 ] i'= \begin{bmatrix} 2& 2 & 1\\ 3 & 3 & 2\\ 4 &4 &3\\ \end{bmatrix} i=234234123
同理可得 j ′ = [ 1 2 3 2 3 4 2 3 4 ] j'= \begin{bmatrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 2 & 3 &4 \\ \end{bmatrix} j=122233344

现在我们可以找到对应关系了,例如:原图中的(1,1)点对应新图中的(2,1)点。旋转处理后的的图像数据为:
g = [ 0 0 f 13 0 f 11 f 12 0 f 23 0 f 21 f 22 f 33 0 f 31 f 32 0 ] g=\begin{bmatrix} 0 & 0 & f_{13} & 0\\ f_{11} & f_{12} & 0 & f_{23} \\ 0 & f_{21} &f_{22} &f_{33} \\ 0 & f_{31} & f_{32} & 0 \end{bmatrix} g=0f11000f12f21f31f130f22f320f23f330
从得到的 g g g矩阵中我们可以看到, g 23 g_{23} g23是一个空穴点,这一点我们需要利用插值法进行填补。其他为0的点则是属于画布上的空白点。

4. 均值插值法

  均值插值法是将空穴像素周围像素值的均值作为填充值填在该空穴点中,如下图所示:
在这里插入图片描述
背景为浅蓝色的点为空穴点,像素值为0。那为什么其他像素值为0的点不是空穴点呢?这里我们给出一个定义:如果一个像素值为0的点的上、下、左、右四个位置处的像素值都不为0,那我们就认为该点是空穴点,需要进行填充。
填充方式就是: g 23 = ( f 13 + f 12 + f 23 + f 22 ) / 4 g_{23}=(f_{13}+f_{12}+f_{23}+f_{22})/4 g23=(f13+f12+f23+f22)/4

二、编程实现

1.C++代码

int main()
{
    cv::Mat img = cv::imread("Lena.bmp");

    cv::Mat gray_img(img.cols,img.rows, CV_8UC1);
    cv::cvtColor(img, gray_img, CV_BGR2GRAY);
    float theta =45;
    float curvature = theta / 180 * CV_PI;

    cv::Mat x = cv::Mat::zeros(img.size(), CV_32FC1);
    cv::Mat y = cv::Mat::zeros(img.size(), CV_32FC1);

    for (int row = 0; row < img.rows; row++)
    {
        for (int col = 0; col < img.cols; col++)
        {
            // 计算新的坐标
            x.at<float>(row, col) = round(row * cos(curvature) - col * sin(curvature));
            y.at<float>(row, col) = round(row * sin(curvature) + col * cos(curvature));
        }
    }
    double x_min, x_max;
    double y_min, y_max;
    
    cv::minMaxLoc(x, &x_min, &x_max);
    cv::minMaxLoc(y, &y_min, &y_max);
    x = x - x_min; 
    y = y - y_min;

    cv::minMaxLoc(x, &x_min, &x_max); // 画布的高
    cv::minMaxLoc(y, &y_min, &y_max); // 画布的宽

    cv::Mat dst = cv::Mat::zeros(x_max+1, y_max+1, CV_8UC1);  //幕布
    cv::Mat flag = cv::Mat::zeros(x_max + 1, y_max + 1, CV_8UC1);

    for (int row = 0; row < gray_img.rows; row++)
    {
        for (int col = 0; col < gray_img.cols; col++)
        {
            int i = (int)x.at<float>(row, col);
            int j = (int)y.at<float>(row, col);
            dst.at<uchar>(i, j) = gray_img.at<uchar>(row, col);
            flag.at<uchar>(i, j) = 1;
        }
    }
    //均值插值法对空穴进行插值
    for (int row = 1; row < dst.rows-1; row++)
    {
        for (int col = 1; col < dst.cols-1; col++)
        {
            if (flag.at<uchar>(row, col - 1) == 1 && flag.at<uchar>(row, col + 1) == 1 &&
                flag.at<uchar>(row - 1, col) == 1 && flag.at<uchar>(row + 1, col) == 1
                && flag.at<uchar>(row, col) == 0)
            {
                dst.at<uchar>(row, col) = uchar((dst.at<uchar>(row, col - 1) + dst.at<uchar>(row, col + 1) +
                    dst.at<uchar>(row - 1, col) + dst.at<uchar>(row + 1, col)) / 4);
            }
        }
    }
    cv::imshow("input", gray_img);
    cv::imshow("output", dst);
    cv::waitKey(0);
    return 0;
}

2.实验结果

在这里插入图片描述


参考资料

1.数字图像处理基础.朱虹.

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

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

相关文章

JAVA并发之谈谈你对AQS的理解

文章目录一、AQS是什么二、AQS具备哪些特性三、用的哪种设计模式四、AQS与锁二者之间的关系五、如何基于AQS实现一把独占锁六、参考资料一、AQS是什么 AQS的全称是 &#xff08;AbstractQueuedSynchronizer &#xff09;&#xff0c;它定义了一套多线程访问共享资源的同步器框架…

【算法基础】(一)基础算法 --- 归并排序

✨个人主页&#xff1a;bit me ✨当前专栏&#xff1a;算法基础 &#x1f525;专栏简介&#xff1a;该专栏主要更新一些基础算法题&#xff0c;有参加蓝桥杯等算法题竞赛或者正在刷题的铁汁们可以关注一下&#x1f339; &#x1f339; &#x1f339; 归并排序&#x1f4a4;一.归…

猴子也能学会的jQuery第十期——jQuery元素操作(上)

&#x1f4da;系列文章—目录&#x1f525; 猴子也能学会的jQuery第一期——什么是jQuery 猴子也能学会的jQuery第二期——引用jQuery 猴子也能学会的jQuery第三期——使用jQuery 猴子也能学会的jQuery第四期——jQuery选择器大全 猴子也能学会的jQuery第五期——jQuery样式操作…

基于拟蒙特卡洛模拟法的随机潮流计算matlab程序

电力系统随机潮流计算中常采用模拟法&#xff0c;该方法原理简单、使用方便&#xff0c;能够精确地模拟实际物理过程&#xff0c;但是简单的蒙特卡洛模拟法收敛速度很慢&#xff0c;要得到精确的结果需要以大量的计算时间为代价。本章在此基础上提出了基于拟蒙特卡洛模拟的随机…

【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-异常值和样本不均衡处理

视频作者&#xff1a;菜菜TsaiTsai 链接&#xff1a;【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili 描述性统计处理异常值 现实数据永远都会有一些异常值&#xff0c;首先我们要去把他们捕捉出来&#xff0c;然后观察他们的性质。注意&#xff0c…

【雷达检测】基于复杂环境下的雷达目标检测技术附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

3.6、媒体接入控制

1、基本概念 有多台主机连接到这根同轴电缆上&#xff0c;共享这跟传输媒体&#xff0c;形成了总线型的局域网。 各主机竞争使用总线&#xff0c;随机的在信道发送数据。 主机 C 与主机 D 同时使用总线来发送数据&#xff0c;这必然会产生所发送信号的碰撞 2、静态划分信道…

二阶锥松弛在配电网最优潮流计算中的应用(IEEE33节点配电网最优潮流算例matlab程序)(yalmip+cplex)

二阶锥规划在配电网最优潮流计算中的应用IEEE33节点配电网最优潮流算例matlab程序&#xff08;yalmipcplex&#xff09; 参考文献&#xff1a;二阶锥规划在配电网最优潮流计算中的应用 最优潮流计算是电网规划、优化运行的重要基础。首先建立了配电网全天有功损耗最小化的最优…

ABAP学习笔记之——第四章:模块化程序

一、子程序&#xff1a; 语法&#xff1a; 参数&#xff1a; 参数(Parameter)是指调用子程序时用于传入、传出的值。子程序中的参数与一般用 DATA语句定义的局部变量相同。调用子程序时使用的参数叫实参(Actual Parameter)&#xff0c;在子程序中使用的参数叫虚参(Formal Par…

nginx(六十八)http_proxy模块 nginx与上游的ssl握手

一 nginx作为客户端与上游的SSL/TLS握手 理解上&#xff1a; nginx作为客户端,此时类似浏览器的角色,发请求建立连接 nginx作为server端与下游进行SSL/TLS握手 ① nginx与后端选择什么样的协议 1&#xff09;如果nginx与上游是局域网内,一般通过http建立请求,不需要进行…

使用flv.js + websokect播放rtsp格式视频流

1.问题背景 在最近的项目中&#xff0c;涉及到海康接入的视频播放的问题&#xff0c;海康这边获取到的视频流是rtsp格式&#xff0c;web端目前没有直接可以播放的组件&#xff0c;于是最开始是后端处理了视频流&#xff0c;返回hls格式的m3u8地址&#xff0c;这样用videojs插件…

进程【JavaEE初阶】

目录 一、操作系统 二、进程 2.1 进程的概念 2.2 进程的管理 2.3 PCB 2.3.1 PCB里面的一些属性 2.3.2 进程的调度 2.3.3 进程的虚拟地址空间 2.3.4 进程间通信 一、操作系统 CPU、存储器、输入设备、输出设备&#xff0c;这些实物看得着摸得到的&#xff0c;都属于 …

web前端-javascript-switch条件分支语句(语法,执行流程,补充)

文章目录条件分支语句(switch 语句)1. 语法&#xff1b;2. 执行流程&#xff1a;2.1. 在执行时会依次将 case 后的条件表达式的值和 switch 后的条件表达式的值进行全等比较2.2. 如果比较结果为 true&#xff0c;则从当前 case 处开始执行代码2.3. 如果比较结果为 false&#x…

【知识网络分析】研究机构合作网络(co-investigator institution)

研究机构合作网络(co-investigator institution) 1 网络数据集读取2 网络最大子群数据获取与精简3 中心点指定网络半径子群获取4 节点中心度相关指标计算1 网络数据集读取 使用GC.networkCoInvestigatorInstitution()方法快速生成研究结构合作网络数据集,其中GC代表着读入p…

解析华为OSPF协议

文章目录 前言一、pandas是 目录 文章目录 OSPF基础 一、报文类型 二、LSA类型 三.LSA在各区域中传播的支持情况 四.邻居状态机 邻居关系 邻接关系 &#xff18;种状态机&#xff1a; OSPF报文认证 OSPF缺省路由 2.读入数据 总结 什么&#xff1f;二、使用步骤 1.引入库2.读入数…

卷积神经网络CNN各层基本知识

卷积神经网络 卷积神经网络(CNN)由输入层、卷积层、激活函数、池化层以及全连接层构成。 INPUT&#xff08;输入层&#xff09;-CONV&#xff08;卷积层&#xff09;-RELU&#xff08;激活函数&#xff09;-POOL&#xff08;池化层&#xff09;-FC&#xff08;全连接层&#…

[VNCTF2022]easyj4va

看源码 输入 /file?url 1报错 用伪协议可以读取到内容 /file?urlfile:///etc/passwd 然后就是查看java字节码文件的目录 file?urlfile:///usr/local/tomcat/webapps/ROOT/WEB-INF 这里官方给了另外一个协议netdoc&#xff0c;跟file用法是一样的&#xff0c;但是这个netd…

JDK动态代理与Cglib动态代理使用详解

JDK动态代理与Cglib动态代理使用详解一、JDK动态代理准备使用二、Cglib动态代理准备使用Enhancer.create(Class type, Callback callback)Enhancer.create((Class superclass, Class[] interfaces, Callback callback))Enhancer.create(Class superclass, Class[] interfaces, …

【学习笔记35】JavaScript计算两个指定日期的时间差

一、要求 计算两个指定日期的时间差&#xff08;2023年元旦到来的时间&#xff09; 二、分析 先获取到两个时间距离1970&#xff08;格林尼时间&#xff09;~~~毫秒数计算两个毫秒数的差值 ----> 得到了总毫秒数计算总毫秒数内, 有多少个完整的天 parseInt(总毫秒数 / 一天的…

会话跟踪技术-session和cookie

会话&#xff08;Session&#xff09;跟踪是Web程序中常用的技术&#xff0c;用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。 Cookie通过在客户端记录信息确定用户身份&#xff0c;Session通过在服务器端记录信息确定用户身份。 Cookie对象与HttpSession对象简…