当前位置: 首页 > news >正文

OpenCV仿射变换详解

1.仿射变换(Affine Transformation)是一种二维线性变换,它保持了图像的"直线性"和"平行性",但不保持角度和长度。一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式。
仿射变换包含以下几种基本变换:
平移(Translation)
旋转(Rotation)
缩放(Scaling)
剪切(Shearing)
函数原型: void warpAffine(InputArray src,OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, intborderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。
第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,需和源图片有一样的尺寸和类型。
第三个参数,InputArray类型的M,2×3的变换矩阵。
第四个参数,Size类型的dsize,表示输出图像的尺寸。
第五个参数,int类型的flags,插值方法的标识符。此参数有默认值INTER_LINEAR(线性插值),可选的插值方式如下:
INTER_NEAREST - 最近邻插值
INTER_LINEAR - 线性插值(默认值)
INTER_AREA - 区域插值
INTER_CUBIC –三次样条插值
INTER_LANCZOS4 -Lanczos插值
CV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.
CV_WARP_INVERSE_MAP –表示M为输出图像到输入图像的反变换,即 。因此可以直接用来做象素插值。否则, warpAffine函数从M矩阵得到反变换。
第六个参数,int类型的borderMode,边界像素模式,默认值为BORDER_CONSTANT。
第七个参数,const Scalar&类型的borderValue,在恒定的边界情况下取的值,默认值为Scalar(),即0。

案例1:使用变换矩阵

// 读取图像Mat src = imread("input.jpg");if (src.empty()) {std::cout << "Could not open or find the image" << std::endl;return -1;}// 定义变换矩阵// 这里创建一个旋转45度并缩放的变换Point2f srcTri[3];Point2f dstTri[3];// 设置源图像和目标图像的三个点srcTri[0] = Point2f(0, 0);srcTri[1] = Point2f(src.cols - 1, 0);srcTri[2] = Point2f(0, src.rows - 1);dstTri[0] = Point2f(src.cols * 0.0, src.rows * 0.33);dstTri[1] = Point2f(src.cols * 0.85, src.rows * 0.25);dstTri[2] = Point2f(src.cols * 0.15, src.rows * 0.7);// 计算仿射变换矩阵Mat warpMat = getAffineTransform(srcTri, dstTri);// 应用仿射变换Mat warpDst = Mat::zeros(src.rows, src.cols, src.type());warpAffine(src, warpDst, warpMat, warpDst.size());

案例2:使用旋转和缩放

Mat src = imread("input.jpg");if (src.empty()) {std::cout << "Could not open or find the image" << std::endl;return -1;}// 获取旋转中心Point2f center(src.cols / 2.0f, src.rows / 2.0f);// 定义旋转角度和缩放因子double angle = 45.0;  // 旋转45度double scale = 0.6;   // 缩放为原来的60%// 获取旋转矩阵Mat rotMat = getRotationMatrix2D(center, angle, scale);// 应用变换Mat dst;warpAffine(src, dst, rotMat, src.size());

关键函数解析
​​getAffineTransform()​​
输入:源图像和目标图像的三个对应点
输出:2×3的仿射变换矩阵
​​getRotationMatrix2D()​​
输入:旋转中心、旋转角度和缩放因子
输出:2×3的旋转矩阵
​​warpAffine()​​
参数:源图像、目标图像、变换矩阵、输出图像大小
功能:应用仿射变换
应用场景
图像校正(如文档扫描后的倾斜校正)
图像配准(将不同视角的图像对齐)
数据增强(在深度学习中生成训练样本)
视角变换(模拟不同视角下的图像)

2.Halcon里面有个很常用的的算子vector_angle_to_rigid,,就是给定两组(x1,y1,angle1),(x2,y2,angle2)构建刚性仿射变换。下面我们用Opencv复刻他的效果。

#include <opencv2/opencv.hpp>
#include <cmath>
using namespace cv;
using namespace std;// 构建刚性仿射变换矩阵
Mat buildRigidAffineMatrix(double x1, double y1, double angle1, double x2, double y2, double angle2) {// 计算平移分量double tx = x2 - x1;double ty = y2 - y1;// 计算旋转角度(角度转弧度)double rad = (angle2 - angle1) * CV_PI / 180.0;double cosTheta = cos(rad);double sinTheta = sin(rad);// 构建刚性变换矩阵Mat affineMat = (Mat_<double>(2, 3) << cosTheta, -sinTheta, tx,sinTheta,  cosTheta, ty);return affineMat;
}// 应用刚性变换到图像
void applyRigidTransformationToImage(const Mat& srcImage, double x1, double y1, double angle1,double x2, double y2, double angle2) {// 构建刚性变换矩阵Mat rigidMat = buildRigidAffineMatrix(x1, y1, angle1, x2, y2, angle2);//注意:如果是为了保证变换后图像尺寸和比例不变,则不需要下面的代码。可以直接进行仿射变换// 计算变换后的图像大小// 由于旋转可能使图像变大,我们需要计算新的边界vector<Point2f> corners = {Point2f(0, 0),Point2f(srcImage.cols, 0),Point2f(srcImage.cols, srcImage.rows),Point2f(0, srcImage.rows)};vector<Point2f> transformedCorners;perspectiveTransform(corners, transformedCorners, rigidMat);// 计算新图像的宽度和高度Rect bbox = boundingRect(transformedCorners);// 调整变换矩阵,使图像不被裁剪rigidMat.at<double>(0, 2) += -bbox.x;rigidMat.at<double>(1, 2) += -bbox.y;// 应用仿射变换Mat dstImage;warpAffine(srcImage, dstImage, rigidMat, bbox.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));}int main() {// 读取图像Mat srcImage = imread("test.jpg");if (srcImage.empty()) {cerr << "Could not open or find the image!" << endl;return -1;}// 定义变换参数double x1 = srcImage.cols / 2.0;  // 图像中心x坐标double y1 = srcImage.rows / 2.0;  // 图像中心y坐标double angle1 = 0;                // 原始角度double x2 = x1 + 50;              // 向右平移50像素double y2 = y1 + 30;              // 向下平移30像素double angle2 = 45;               // 旋转45度// 应用刚性变换applyRigidTransformationToImage(srcImage, x1, y1, angle1, x2, y2, angle2);return 0;
}

关键步骤解析
​​构建刚性变换矩阵​​:
计算从(x1,y1)到(x2,y2)的平移量(tx, ty)
计算从angle1到angle2的旋转角度
构建2×3的仿射变换矩阵
​​处理图像边界问题​​:
计算原始图像四个角点变换后的位置
使用boundingRect确定变换后图像的最小包围矩形
调整变换矩阵,使变换后的图像完全可见
​​应用变换​​:
使用warpAffine函数应用刚性变换
设置插值方法(INTER_LINEAR)和边界填充方式(BORDER_CONSTANT)
在这里插入图片描述
在这里插入图片描述

http://www.dtcms.com/a/264661.html

相关文章:

  • 【飞算JavaAI】智能开发助手赋能Java领域,飞算JavaAI全方位解析
  • 红海云签约东莞科创金融集团,科创金融行业人力资源数字化
  • 论文阅读笔记——VGGT: Visual Geometry Grounded Transformer
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | ButtonRippleEffect(按钮涟漪效果)
  • 基于[coze][dify]搭建一个智能体工作流,使用第三方插件抓取热门视频数据,自动存入在线表格
  • Node.js-http模块
  • mac Maven配置报错The JAVA_HOME environment variable is not defined correctly的解决方法
  • 21、企业行政办公(OA)数字化转型:系统如何重塑企业高效运营新范式
  • Android Native 之 inputflinger进程分析
  • 硬件选型与组网规划S7-300以太网模块适配性与网络架构搭建
  • 学习笔记(27):线性回归基础与实战:从原理到应用的简易入门
  • 利器:NPM和YARN及其他
  • 楚存科技SD NAND贴片式T卡—高性能存储解决方案、赋能AI智能硬件
  • 《Jaccard距离》算法:集合差异性度量的核心工具
  • 第三章 计算机网络体系结构
  • 【前端】基础 - HTML基础标签和样式设置
  • 深入理解装饰器模式:动态扩展对象功能的灵活设计模式
  • 前端Base64格式文件上传详解:原理、实现与最佳实践
  • STM32 使用 TinyUSB
  • 03-Linux内核驱动模块加载
  • visual studio Code运行vue项目
  • 4K超高清无缝切换与画面分割矩阵
  • gin框架 中间件 是在判断路由存在前执行还是存在后执行的研究
  • 【AI智能体】基于Coze 制作高质量PPT实战操作详解
  • 打造Docker Swarm集群服务编排部署指南:从入门到精通
  • 降低网络安全中的人为风险:以人为本的路径
  • mr 任务运行及jar
  • FAISS 简介及其与 GPT 的对接(RAG)
  • 人机融合智能 | 人智交互中的人类状态识别
  • WSL2与Windows交换端口命令记录