【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列和通过上面的例子,可以快速高效的实现平移、缩放和旋转等功能。
相关文章:
【C++】【Opencv】cv::warpAffine()仿射变换函数详解,实现平移、缩放和旋转等功能
仿射变换是一种二维变换,它可以将一个二维图形映射到另一个二维图形上,保持了图形的“形状”和“大小”不变,但可能会改变图形的方向和位置。仿射变换可以用一个线性变换矩阵来表示,该矩阵包含了六个参数,可以进行平移…...
WPF实现右键菜单
在WPF中,创建上下文菜单(通常称为“右键菜单”)是通过使用ContextMenu控件来实现的。你可以在XAML中声明上下文菜单,并将其关联到任何FrameworkElement。以下是如何在WPF中实现上下文菜单的基本步骤: 1. 在XAML中定义…...
Java智慧工地SaaS管理平台源码:AI/云计算/物联网
智慧工地是指运用信息化手段,围绕施工过程管理,建立互联协同、智能生产、科学管理的施工项目信息化生态圈,并将此数据在虚拟现实环境下与物联网采集到的工程信息进行数据挖掘分析,提供过程趋势预测及专家预案,实现工程…...
【漏洞复现】通达oa 前台sql注入
漏洞描述 通达OA(Office Automation)是一款企业级协同办公软件,旨在为企业提供高效、便捷、安全、可控的办公环境。它涵盖了企业日常办公所需的各项功能,包括人事管理、财务管理、采购管理、销售管理、库存管理、生产管理、办公自动化等。通达OA支持PC端和移动端使用,可以…...
机器学习笔记 - Ocr识别中的文本检测EAST网络概述
一、文本检测 文本检测简单来说就是找到图像中可以出现文本的区域。例如,请参见下图,其中在检测到的文本周围绘制了绿色边框。 在进行文本检测时,你可能会遇到两种情况 具有结构化文本的图像:这是指具有干净/均匀背景和常规字体的图像。文本大多密集,行结构正确,…...
【SQL server】数据库、数据表的创建
创建数据库 --如果存在就删除 --所有的数据库都存在sys.databases当中 if exists(select * from sys.databases where name DBTEST)drop database DBTEST--创建数据库 else create database DBTEST on --数据文件 (nameDBTEST,--逻辑名称 字符串用单引号filenameD:\DATA\DBT…...
vue的生命周期分别是什么?
Vue的生命周期分为8个阶段,分别是: beforeCreate:实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 created:实例已经创建完成后被调用,这时候实例已完成以下的配置&#…...
Java拼图游戏
运行出的游戏界面如下: 按住A不松开,显示完整图片;松开A显示随机打乱的图片。 User类 package domain;/*** ClassName: User* Author: Kox* Data: 2023/2/2* Sketch:*/ public class User {private String username;private String password…...
Vue框架的element组件table文字居中
1.直接上代码 <el-table max-height"500px" :data"datas.roles" style"width: 100%" border :header-cell-style"{textAlign: center}" :cell-style"{ textAlign: center }"><el-table-column prop"id" …...
科技创新 共铸典范 | 江西卫健办邓敏、飞图影像董事长洪诗诗一行到访拓世科技集团,提振公共卫生事业发展
2023年11月15日,拓世科技集团总部迎来了江西省卫健项目办项目负责人邓敏、江西飞图影像科技有限公司董事长洪诗诗一行的考察参观,集团董事长李火亮、集团高级副总裁方高强进行热情接待。此次多方交流,旨在共同探讨携手合作,激发科…...
Linux安装OpenCV并配置VSCode环境
Linux安装OpenCV并配置VSCode环境 安装OpenCV环境安装必需工具下载并解压OpenCV库(Opencv Core Modules和opencv_contrib)创建构建目录,进行构建验证构建结果安装验证安装结果 配置VSCode环境创建项目文件修改配置信息执行程序 安装环境 Ubun…...
Django(ORM事务操作|ORM常见字段类型|ORM常见字段参数|关系字段|Meta元信息)
文章目录 ORM事务操作什么是事务?事务的产生事务的四大特征ORM中如何使用事务 ORM字段类型常用字段与不常用字段类型ORM还支持用户自定义字段类型 ORM字段参数关系字段ForeignKey外键on_delete参数设置的值 OneToOneField与ForeignKey的区别多对多关系建立的方式ORM…...
【mujoco】Ubuntu20.04配置mujoco210
【mujoco】Ubuntu20.04配置mujoco210 文章目录 【mujoco】Ubuntu20.04配置mujoco2101. 安装mujoco2102. 安装mujoco-py3.使用render时报错Reference 本文简要介绍一下如何在ubuntu20.04系统中配置mujoco210,用于强化学习。 1. 安装mujoco210 在官方资源里找到http…...
【洛谷 P3853】[TJOI2007] 路标设置 题解(二分答案+循环)
[TJOI2007] 路标设置 题目背景 B 市和 T 市之间有一条长长的高速公路,这条公路的某些地方设有路标,但是大家都感觉路标设得太少了,相邻两个路标之间往往隔着相当长的一段距离。为了便于研究这个问题,我们把公路上相邻路标的最大…...
蓝桥杯 vector
vector的定义和特性 注意:vector需要开C11标准 vector的常用函数 push_back():将元素添加到vector末尾 pop_back():删除vector末尾的元素 begin()和end():返回指向vector第一个元素和最后一个元素之后一个位置的迭代器。 示例 vector<int> vec{10,20,30};f…...
ai绘画部署教程
在部署AI绘画Web环境的过程中,你提供了一些关键步骤。以下是一些详细说明: 1. 克隆webui 首先,通过以下命令从GitHub上克隆webui的代码: git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 这将下载webui的源…...
策略模式的应用——应对频繁的需求变更
秋招结束后,间接性堕落了一段时间,学习几乎停止下来了。内心甚是焦灼,感觉生活很无趣!为了在参加工作后能够快速上手和成为一名优秀的中级开发者,从这篇文章开始将不断学习优秀的编码经验,学习是永无止境的…...
qt-C++笔记之treeWidget初次使用
qt-C笔记之treeWidget初次使用 code review! 文章目录 qt-C笔记之treeWidget初次使用1.运行2.文件结构3.main.cpp4.widget.h5.widget.cpp6.widget.ui7.main.qrc8.qt_widget_test.pro9.options.png 1.运行 2.文件结构 3.main.cpp 代码 #include "widget.h"#include…...
SQL零基础入门教程,贼拉详细!贼拉简单! 速通数据库期末考!(八)
FULL OUTER JOIN 除了前面讲到的 INNER JOIN(内连接)、LEFT JOIN(左连接)、RIGHT JOIN(右连接),还有另外一种关联方式,即 FULL OUTER JOIN(全外连接) FULL O…...
C语言编程陷阱(八)
陷阱36:不要使用指针作为函数的返回值 有时候,我们可能想要用一个函数来返回一个指针,比如返回一个动态分配的内存,或者返回一个数组的某个元素的地址。但是,如果我们不小心,我们可能会犯一个很常见的错误,就是返回一个局部变量的地址。例如,看看下面的代码: #inclu…...
大模型微调:教科书级数据工程,200条数据提升170%BLEU!揭秘金融与医疗领域爆款模型的底层逻辑
本文深入探讨了大模型微调的数据工程与评估体系。核心观点是:高质量数据比海量样本更重要,通过精细的数据过滤和选择,即使是小数据集也能显著提升模型效果。文章对比了SFT、RLHF、GRPO三种主流微调方法,并以金融客服和医疗问答为例…...
ComfyUI自定义节点开发指南:从零构建你的专属AI工具链
1. 为什么需要自定义ComfyUI节点? 第一次用ComfyUI做AI绘画时,我就被它灵活的节点式操作吸引了。但用着用着发现一个问题:官方提供的节点虽然强大,但总有些特殊需求无法满足。比如想给生成的图片自动打水印、批量处理文件夹里的图…...
高效掌握Mermaid:从文本到可视化的实战指南
高效掌握Mermaid:从文本到可视化的实战指南 【免费下载链接】mermaid mermaid-js/mermaid: 是一个用于生成图表和流程图的 Markdown 渲染器,支持多种图表类型和丰富的样式。适合对 Markdown、图表和流程图以及想要使用 Markdown 绘制图表和流程图的开发者…...
nomic-embed-text-v2-moe保姆级教程:Gradio自定义CSS主题与响应式布局
nomic-embed-text-v2-moe保姆级教程:Gradio自定义CSS主题与响应式布局 1. 从零开始:认识nomic-embed-text-v2-moe 如果你正在寻找一个既强大又好用的文本嵌入模型,特别是需要处理多语言内容,那么nomic-embed-text-v2-moe绝对值得…...
StructBERT-Large本地化部署实战:无需联网、不传数据、隐私安全的语义匹配解决方案
StructBERT-Large本地化部署实战:无需联网、不传数据、隐私安全的语义匹配解决方案 你是不是经常需要判断两句话是不是一个意思?比如,检查用户提交的答案是否和标准答案一致,或者判断两篇新闻稿是不是在说同一件事。过去…...
OpenClaw成本优化方案:自建Qwen3-VL:30B替代高价多模态API
OpenClaw成本优化方案:自建Qwen3-VL:30B替代高价多模态API 1. 为什么需要关注OpenClaw的成本问题 第一次用OpenClaw完成多模态任务时,我被账单吓了一跳。当时需要处理200张产品图片的分类和描述生成,调用某商业多模态API后,费用…...
CSSCI论文写作03:确定论文的选题
什么是选题 选题:选择一个适合的研究指向!!! 选择: 而不是创造,创新是内在要求 你要坚信:所有的选题都有前人关注过研究过,我们不求“栽树”,只求“乘凉”,填补什么空白,只能说明自己的浅薄无知。 适合: 个人经验的学术表达,找到那双穿在自己脚上的鞋子没有不能…...
华为MateBook D14安装Ubuntu16避坑指南:WiFi/蓝牙/触控板驱动一键搞定
华为MateBook D14安装Ubuntu 16.04驱动优化全攻略 华为MateBook D14作为一款高性价比轻薄本,在安装Ubuntu 16.04时可能会遇到WiFi、蓝牙和触控板驱动不兼容的问题。这主要源于硬件迭代速度远超Linux内核更新周期——你的笔记本搭载了新一代无线网卡和输入设备&#…...
【高通Camera_Tuning】优化树荫下及背景绿植时白平衡偏色问题(一)
参考案例:在室外拍摄时白平衡正常,但遇到树荫下或背景有绿植时出现偏色(偏蓝)问题。可通过修改绿区解决偏色问题。解决方法:1.开启Green zone在3A文件 -- /* Green */ -- /* Green Projection Enable */将/* Green Pr…...
电子元器件检测数据集VOC+YOLO格式1032张5类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数):1032标注数量(xml文件个数):1032标注数量(txt文件个数):1032标注类别…...
