【C++】【Opencv】cv::warpAffine()仿射变换函数详解,实现平移、缩放和旋转等功能

仿射变换是一种二维变换,它可以将一个二维图形映射到另一个二维图形上,保持了图形的“形状”和“大小”不变,但可能会改变图形的方向和位置。仿射变换可以用一个线性变换矩阵来表示,该矩阵包含了六个参数,可以进行平移、缩放、旋转等操作。通过原理、函数和示例进行解析,帮助大家理解和使用。

下面我们将依次实现平移、旋转、缩放和仿射变换等功能,使用C++语言和OpenCV库。

目录

  • 原理和函数
    • 原理
    • warpAffine()函数详解
  • 示例
    • 平移
      • 原理
      • 运行示例
    • 缩放
      • 原理
      • 缩小示例
      • 放大示例
    • 旋转
      • 原理
      • 顺时针示例
      • 逆时针示例
  • 总结

原理和函数

原理

在这里插入图片描述在这里插入图片描述
由于矩阵A的最后一行为(0,0,1),所以认为A是仿射变换矩阵,变换类型主要包括平移、缩放和旋转。

warpAffine()函数详解

warpAffine() 是 OpenCV 库中的一个函数,用于进行二维仿射变换。该函数将输入图像映射到输出图像,应用仿射变换。

函数原型如下:

void cv::warpAffine(InputArray src, OutputArray dst, InputArray mat, Size dsize = Size(), int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, Scalar borderValue = Scalar());参数详解:src:输入图像,必须是单通道或三通道的8位或32位浮点型图像。
dst:输出图像,其大小和类型与输入图像相同。
mat:2x3的变换矩阵。
dsize:输出图像的大小,如果这个参数为 Size() ,则输出图像的大小将与输入图像相同。
flags:用于指定插值的方法,默认为线性插值。可用的选项有 INTER_NEAREST, INTER_LINEAR, INTER_CUBIC 等。
borderMode:用于指定如何处理输出图像边缘的像素,默认为常量填充模式。可用的选项有 BORDER_CONSTANT, BORDER_REPLICATE, BORDER_WRAP 等。
borderValue:用于指定填充的边界值,默认为0。

这个函数使用仿射变换来将输入图像映射到输出图像。仿射变换包括旋转、缩放、平移等操作,但不包括扭曲和剪切。这个函数非常有用,特别是在需要将图像映射到另一个大小或以特定方式旋转或倾斜图像时。

示例

平移

原理

平移变换可以用一个3x3的变换矩阵来表示,其中第一行和第二行表示原始图像的行向量和列向量,第三行表示变换后的行向量和列向量,和原理部分类似,但有些版本只需要设置一个2x3的变换矩阵即可,可以省略第三行。在本例中,即定义的是2x3的变换矩阵,我们将原始图像向右移动100个像素,向下移动300个像素。其中,数值为正,则向正方向移,数值为负,则向反向相移。
在这里插入图片描述
如上述矩阵转换矩阵,只需要设置第一行的第三个元素tx和第二行第三列的ty即可,体现在2行3列的矩阵中如下面运行示例中的100和300所示。

运行示例

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat src = imread("ceshi.jpg");if (src.empty()) {cout << "Could not read the source image" << endl;return -1;}Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, 100, 0, 1, 300);Mat dst;warpAffine(src, dst, trans_mat, src.size());imshow("Source Image", src);imshow("Affine Transformed Image", dst);imwrite("pingyi.jpg", dst);waitKey(0);return 0;
}

在代码中,Mat trans_mat = (Mat_<double>(2, 3) << 1, 0, 100, 0, 1, 300);是定义的一个2行3列的转换矩阵,第一行是右移100,第二行是下移300。最后,我们使用warpAffine()函数进行仿射变换,将原始图像映射到输出图像中,并显示原始图像和变换后的图像。运行可以看到相应的效果,如下图所示。
在这里插入图片描述
上面为原图,下面为平移后的图像。
在这里插入图片描述

缩放

原理

仿射变换中的缩放指的是对图像进行等比例的放大或缩小。在仿射变换矩阵中,可以通过设置第一行和第二行的元素来控制缩放。
在这里插入图片描述
由上面的平移可知,第一行第三列和第二行第三列的数值是控制平移的,在此处可知,第一行第一列和第二行第二列是用于控制x轴和y轴的缩放比例的,在下面的运行示例中也可以看出缩放因子在的位置与此相对应。

缩小示例

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat src = imread("ceshi.jpg");if (src.empty()) {cout << "Could not read the source image" << endl;return -1;}// 设置缩放比例double scale = 0.5;// 计算缩放矩阵Mat scale_mat = (Mat_<double>(2, 3) << scale, 0, 0, 0, scale, 0);// 进行仿射变换Mat dst;warpAffine(src, dst, scale_mat, src.size());// 显示原始图像和变换后的图像imshow("Source Image", src);imshow("Affine Transformed Image", dst);imwrite("suoxiao.jpg", dst);waitKey(0);return 0;
}

在上面的代码中,我们首先读取一张名为“ceshi.jpg”的图像,然后设置缩放比例为0.5。接着,我们计算缩放矩阵,其中第一行和第二行的前两个元素分别表示水平方向和垂直方向的缩放比例,第三行和第四行的前两个元素为0,表示不进行平移操作。最后,我们使用warpAffine()函数进行仿射变换,将原始图像映射到输出图像中,并显示原始图像和变换后的图像。变换后的效果如下图所示。
在这里插入图片描述

放大示例

此处,我们把缩放因子设置为1.5,即放大,

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat src = imread("ceshi.jpg");if (src.empty()) {cout << "Could not read the source image" << endl;return -1;}// 设置缩放比例double scale = 1.5;// 计算缩放矩阵Mat scale_mat = (Mat_<double>(2, 3) << scale, 0, 0, 0, scale, 0);// 进行仿射变换Mat dst;warpAffine(src, dst, scale_mat, src.size());// 显示原始图像和变换后的图像imshow("Source Image", src);imshow("Affine Transformed Image", dst);imwrite("fangda.jpg", dst);waitKey(0);return 0;
}

放大的效果如下图所示。
在这里插入图片描述
相当于把图像一部分放大,但显示的内容比原图就少了很多,因为图像的总体大小没有改变。

旋转

原理

在这里插入图片描述
在这里插入图片描述

此处,以原点(0,0)坐标为中心进行,α 是旋转角度。
旋转矩阵的元素是由旋转角度和旋转中心计算得出的。假设我们有一个二维坐标系,其中原点是旋转中心,x轴正方向是右方,y轴正方向是上方。现在我们要将点 (x, y) 绕原点逆时针旋转θ角度,那么旋转矩阵可以表示为:

[ cosα, -sinα, 0 ]
[ sinα,  cosα, 0 ]
其中,cosθ 和 sinθ 是使用弧度值计算得出的。

也可以是如下公式:
在这里插入图片描述

若为上述A变换矩阵,则当α 为正时,旋转方向为顺时针;当 α 为负时,旋转方向为逆时针。
同时,另外一种情况与此相反,如变换矩阵为:

[ cosα, sinα, 0 ]
[ -sinα,  cosα, 0 ]

在这里插入图片描述
则当α 为正时,旋转方向为逆时针;当 α 为负时,旋转方向为顺时针。
此外,也可以控制α 的值,如α 为45和为-45逆顺情况是相反的。

下面进行两个示例,分别进行顺时针和逆时针旋转。

顺时针示例

#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {Mat src = imread("ceshi.jpg");if (src.empty()) {cout << "Could not read the source image" << endl;return -1;}// 设置旋转角度double angle = 45;// 计算旋转矩阵Mat rot_mat = (Mat_<double>(2, 3) << cos(angle), -sin(angle), sin(angle), cos(angle), 1, 0);cout<< cos(angle) <<endl;cout << -sin(angle) << endl;cout << sin(angle) << endl;//rot_mat = rot_mat * 100; // 设置旋转中心点,这里将图像中心设置为旋转中心// 进行仿射变换Mat dst;warpAffine(src, dst, rot_mat, src.size());// 显示原始图像和变换后的图像imshow("Source Image", src);imshow("Affine Transformed Image", dst);imwrite("shunshizhen.jpg", dst);waitKey(0);return 0;
}

上述代码中设置的double angle = 45;为旋转角度,45为正数,所以是逆时针旋转,同时,(Mat_<double>(2, 3) << cos(angle), -sin(angle), sin(angle), cos(angle), 1, 0);转换矩阵表示当α 为正时,旋转方向为顺时针;当 α 为负时,旋转方向为逆时针。
旋转结果为:
在这里插入图片描述

逆时针示例

(1)通过改变 α的值,如将上面顺时针的45变为-45.
(2)改变变换矩阵的顺序,如使用Mat rot_mat = (Mat_<double>(2, 3) << cos(angle), sin(angle), -sin(angle), cos(angle), 1, 0);替换上面代码中的转换矩阵。
以原点(0,0)为中心,逆时针旋转45度效果图如下:
在这里插入图片描述

总结

我们可以看出,在使用warpAffine()函数是比较方便的,通过使用定义2行3列和通过上面的例子,可以快速高效的实现平移、缩放和旋转等功能。

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

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

相关文章

PXE高效批量网络装机

目录 一.PXE 1. 系统装机的三种引导方式 2. 系统安装过程 3. 光盘安装相关文件 4. PXE简介 5. 实现过程 6. PXE优点 二.PXE实现过程 1. 实验准备 2. 搭建DHCP服务器 3. 配置TFTP服务器 4. 准备pxelinu.0文件 5. 挂载镜像准备内核、驱动文件 6. 手写配置文件 7. 准…

linux如何使用shell远程连接

简介&#xff1a;本文的一切条件基于redhat的linux操作系统。 1、创建虚拟机&#xff1a; 如有需要&#xff0c;请转至【linux基础】在VMware上安装RHEL9详细教程_融社的博客-CSDN博客 &#xff08;如若侵权&#xff0c;该篇立删&#xff09; 2、使用命令查看网段信息 打…

生命科学领域 - FAIR原则和如果使数据FAIR化

2016年&#xff0c;《Scientific Data》发表了《科学数据管理和监督的FAIR指导原则》&#xff08;FAIR Guiding Principles for scientific data management and stewardship&#xff09;。文章旨在提供指导方针&#xff0c;以提高数字资产的可发现性、可访问性、互操作性和重用…

代码随想录算法训练营第25天|216.组合总和III 17.电话号码的字母组合

JAVA代码编写 216. 组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k …

面向未来的自动化:拥抱机器人即服务(RaaS)

01. RaaS是什么&#xff1f; 对于希望实现业务流程自动化的公司来说&#xff0c;机器人通常是一笔巨大的资本支出。由于机器人非常昂贵&#xff0c;公司可能需要等待数年才能看到投资回报。正是由于这一现实&#xff0c;许多较小的组织无法投资机器人。 但一些机器人公司正在采…

【音视频基础】AVI文件格式

AVI文件采用的是RIFF文件结构方式。波形音频wave&#xff0c;MIDI和数字视频AVI都采用这种格式存储。 AVI文件的整体结构如下图所示 构造RIFF文件的基本单元叫做数据块&#xff08;Chunk&#xff09;&#xff0c;每个数据块包含3个部分 4字节的数据块标记&#xff08;或者叫…

【C语言数据结构】单链表

目录 分析顺序表和链表实现单链表打印链表动态申请一个节点尾插头插尾删头删查找值函数单链表在pos位置之前插入x单链表在pos位置之后插入x删除pos位置单链表删除pos位置之后的值释放内存空间 分析顺序表和链表 如下图可以看出顺序表的优点 1.尾插尾删足够快 2.下标随机访问和修…

Git安装与常用命令

Git简介&#xff1a; Git是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或大或小的项目。Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。Git与常用的版本控制工具CVS、Subversion等不同&#xff0c;它采用了分布式…

zsh和ohmyzsh安装指南+插件推荐

文章目录 1. 安装指南2. 插件配置指南3. 参考信息 1. 安装指南 1. 安装 zsh sudo apt install zsh2. 安装 Oh My Zsh 国内访问GitHub sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"这将安装 Oh My Zsh 和所…

验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信你对这篇博客也感兴趣o (ˉ▽ˉ&#xff1b;) &#x1f4dc;表白墙/留言墙 —— 中级SpringBoot项目&#xff0c;MyBatis技术栈MySQL数据库开发&#xff0c;练手项目前后端开发(带完整源码) 全方位全步骤手…

强烈 推荐 13 个 Web前端在线代码IDE

codesandbox.io&#xff08;国外&#xff0c;提供免费空间&#xff09; 网址&#xff1a;https://codesandbox.io/ CodeSandbox 专注于构建完整的 Web 应用程序&#xff0c;支持多种流行的前端框架和库&#xff0c;例如 React、Vue 和 Angular。它提供了一系列增强的功能&…

【数据预处理2】数据预处理——数据标准化

数据标准化 1. 什么是标准化&#xff1f;   数据标准化是一个常用的数据预处理操作&#xff0c;目的是将不同规格的数据转换到统一规格或不同分布的数据转换到某个特定范围&#xff0c;以减少规模、特征、分布差异等对模型的影响。这种操作也叫作无量纲化。   除了用作模型…