Affine Transformations(仿射变换)

2023-05-16

英文版原文链接
先修教程:Remapping(重映射)
下一教程:Histogram Equalization(直方图均衡化)

文章目录

    • 结果
    • 目标
    • 原理
        • 什么是仿射变换?
        • 我们如何得到一个仿射变换?
    • 代码
        • 这个程序是做什么的?
        • 代码如下所示:
    • 解释

结果

  • 在编译代码之后,我们可以将图像的路径作为参数提供给它。例如,像这样的图片:
    在这里插入图片描述
  • 应用第一个仿射变换后得到:
    在这里插入图片描述
  • 最后,在应用一个负的旋转(记住负的意思是顺时针)和一个比例因子之后,我们得到:
    在这里插入图片描述

目标

此教程我们将学会:

  • 使用OpenCV函数 cv::warpAffine 实现简单的重新映射例程。
  • 使用OpenCV函数 cv::getRotationMatrix2D 获得一个 2×3 旋转矩阵

原理

什么是仿射变换?

1、以矩阵乘法(线性变换)和向量加法(平移变换)的形式表示的一种变换。
2、由上可知,我们可以用仿射变换来表示:

  • a、旋转(线性变换)
  • b、平移(向量加法)
  • c、尺度变化(线性变换)

可以看到,在本质上,仿射变换表示两个图像之间的关系。
3、表示仿射变换的常用方法是使用一个2 × 3的矩阵。
A = [ a 00 a 01 a 10 a 11 ] 2 × 2 B = [ b 00 b 10 ] 2 × 1 A = \begin{bmatrix} a_{00} & a_{01} \\ a_{10} & a_{11} \end{bmatrix}_{2 \times 2} B = \begin{bmatrix} b_{00} \\ b_{10} \end{bmatrix}_{2 \times 1} A=[a00a10a01a11]2×2B=[b00b10]2×1
M = [ A B ] = [ a 00 a 01 b 00 a 10 a 11 b 10 ] 2 × 3 M = \begin{bmatrix} A & B \end{bmatrix} = \begin{bmatrix} a_{00} & a_{01} & b_{00} \\ a_{10} & a_{11} & b_{10} \end{bmatrix}_{2 \times 3} M=[AB]=[a00a10a01a11b00b10]2×3

考虑到我们要变换一个二维向量 X = [ x y ] X = \begin{bmatrix}x \\ y\end{bmatrix} X=[xy] ,通过使用A和B,我们也可以这样做:
T = A ⋅ [ x y ] + B T = A \cdot \begin{bmatrix}x \\ y\end{bmatrix} + B T=A[xy]+B 或者 T = M ⋅ [ x , y , 1 ] T T = M \cdot [x, y, 1]^{T} T=M[x,y,1]T
T = [ a 00 x + a 01 y + b 00 a 10 x + a 11 y + b 10 ] T = \begin{bmatrix} a_{00}x + a_{01}y + b_{00} \\ a_{10}x + a_{11}y + b_{10} \end{bmatrix} T=[a00x+a01y+b00a10x+a11y+b10]

我们如何得到一个仿射变换?

1、我们提到过仿射变换基本上是两个像之间的关系。关于这种关系的信息大致可以通过两种方式获得:

  • a、我们知道 X X X T T T,我们也知道它们是相关的。那么我们的任务就是找到 M M M
  • b、我们知道 M M M X X X。为了得到 T T T,我们只需要应用 T = M ∗ X T= M*X T=MX。我们对于 M M M的信息可以是显式的(即具有2×3矩阵),也可以是点之间的几何关系。

2、让我们用更好的方式来解释(b)。因为 M M M与2张图像相关,我们可以分析它与两张图像中的3个点相关的最简单的情况。请看下图
在这里插入图片描述
点1、2和3(在图1中形成一个三角形)被映射到图2中,仍然形成一个三角形,但是现在它们已经显著地改变了。如果我们找到这3个点的仿射变换(您可以选择您喜欢的),那么我们可以将这个找到的关系应用到图像中的所有像素。

代码

这个程序是做什么的?

  • 加载一张图像
  • 对图像应用仿射变换。这个变换矩阵是由三个点之间的关系得到的。为此,我们使用了函数 cv::warpAffine
  • 在仿射变换后对图像应用旋转。这个旋转是以图像中心为旋转点的。
  • 等待,直到用户退出程序

代码如下所示:

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
    if( src.empty() )
    {
        cout << "Could not open or find the image!\n" << endl;
        cout << "Usage: " << argv[0] << " <Input image>" << endl;
        return -1;
    }
    Point2f srcTri[3];
    srcTri[0] = Point2f( 0.f, 0.f );
    srcTri[1] = Point2f( src.cols - 1.f, 0.f );
    srcTri[2] = Point2f( 0.f, src.rows - 1.f );
    Point2f dstTri[3];
    dstTri[0] = Point2f( 0.f, src.rows*0.33f );
    dstTri[1] = Point2f( src.cols*0.85f, src.rows*0.25f );
    dstTri[2] = Point2f( src.cols*0.15f, src.rows*0.7f );
    Mat warp_mat = getAffineTransform( srcTri, dstTri );
    Mat warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
    Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
    double angle = -50.0;
    double scale = 0.6;
    Mat rot_mat = getRotationMatrix2D( center, angle, scale );
    Mat warp_rotate_dst;
    warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
    imshow( "Source image", src );
    imshow( "Warp", warp_dst );
    imshow( "Warp + Rotate", warp_rotate_dst );
    waitKey();
    return 0;
}

解释

  • 加载图片
	CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
    Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ) );
    if( src.empty() )
    {
        cout << "Could not open or find the image!\n" << endl;
        cout << "Usage: " << argv[0] << " <Input image>" << endl;
        return -1;
    }
  • 仿射变换:正如我们在上面的行中所解释的,我们需要两组3个点的集合来导出仿射变换矩阵。看一看:
    Point2f srcTri[3];
    srcTri[0] = Point2f( 0.f, 0.f );
    srcTri[1] = Point2f( src.cols - 1.f, 0.f );
    srcTri[2] = Point2f( 0.f, src.rows - 1.f );
    
    Point2f dstTri[3];
    dstTri[0] = Point2f( 0.f, src.rows*0.33f );
    dstTri[1] = Point2f( src.cols*0.85f, src.rows*0.25f );
    dstTri[2] = Point2f( src.cols*0.15f, src.rows*0.7f );

你可以画出这些点来更好地了解它们是如何变化的。它们的位置与示例图(在原理部分)中描述的位置大致相同。您可能会注意到由3个点定义的三角形的大小和方向会发生变化。

  • 利用这两组点,我们利用OpenCV函数 cv::getAffineTransform:
	Mat warp_mat = getAffineTransform( srcTri, dstTri );

我们得到一个 2 × 3 2×3 2×3矩阵作为输出(在本例中为 warp_mat)

  • 然后我们将刚刚建立的仿射变换应用到 src 图像
    Mat warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

有以下参数:
1)src:输入图像
2)warp_dst:输出图像
3)warp_mat:仿射变换
4) warp_dst.size():输出图像的期望大小
我们刚刚得到了我们的第一个变换图像!我们将在 1bit 中显示它。在那之前,我们还想旋转它…

  • 旋转:要旋转一个图像,我们需要知道两件事:
    1)图像旋转的中心
    2)要旋转的角度。在OpenCV中,正角是逆时针的
    3)可选:一个比例因子
    我们用以下代码片段定义这些参数:
    Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
    double angle = -50.0;
    double scale = 0.6;
  • 我们使用OpenCV函数 cv::getRotationMatrix2D 生成旋转矩阵,它返回一个 2 × 3 2×3 2×3矩阵(在本例中为rot_mat)。
    Mat rot_mat = getRotationMatrix2D( center, angle, scale );
  • 我们现在将建立的旋转矩阵应用到先前的输出上:
    Mat warp_rotate_dst;
    warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
  • 最后,我们显示我们的结果以及原始图像:
    imshow( "Source image", src );
    imshow( "Warp", warp_dst );
    imshow( "Warp + Rotate", warp_rotate_dst );
  • 等待用户退出程序
    waitKey();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Affine Transformations(仿射变换) 的相关文章

  • Markdown 公式指导手册

    Markdown 公式指导手册
  • Linux学习

    文章目录 一 基础入门二 Linux 命令总结一 Linux 目录命令 https blog csdn net weixin 42715287 article details 105825021 二 Linux 文件管理命令 https e
  • Linux命令总结之文件管理命令

    文章目录 二 Linux 文件管理命令1 96 which 96 命令到底什么是命令 xff1f 2 96 whereis 96 命令3 96 locate 96 命令4 96 find 96 命令5 96 xargs 96 命令 二 Li
  • Linux命令总结之文本编辑命令

    文章目录 Linux 文本编辑命令1 96 wc 96 命令2 96 grep 96 命令3 96 正则表达式 96 命令4 96 cut 96 命令5 96 paste 96 命令6 96 tr 96 命令7 96 sort 96 命令8
  • Linux命令总结之Linux 磁盘管理命令

    文章目录 Linux 磁盘管理命令1 96 df 96 命令2 96 du 96 命令3 96 time 96 命令 Linux 磁盘管理命令 1 df命令 linux 中 df 命令的功能是用来检查 linux 服务器的文件系统的磁盘空间
  • linux基础操作之一

    文章目录 1 基本概念及操作常用快捷键 xff1a 2 用户及文件权限管理1 Linux 用户管理1 查看用户 xff1a 2 创建账户 xff1a 3 用户组4 删除用户和用户组5 鲲鹏服务器安装 96 perf 96 6 阿里云服务器安
  • 重庆思庄Linux技术分享-linux中VDO的使用

    VDO xff08 Virtual Data Optimize虚拟数据优化 xff09 通过压缩或删除存储设备上的数据来优化存储空间 VDO层放置在现有块存储设备例如RAID设备或本地磁盘的顶部 这些块设备也可以是加密设备 存储层 xff0
  • 排序算法之快排

    1 快排 快速排序算法的关键在于先在数组中选一个数字 xff0c 接下来把数组中的数字分成两部分 span class token comment achieve quick sorting span span class token ma

随机推荐

  • 排序算法之归并排序

    充分利用了把大问题转化成一个个小的子问题的思想 xff08 由迭代或递归来实现 xff09 span class token comment achieve merge sorting span span class token macro
  • 排序算法之堆排序(附源码)

    1 将顺序存储的数据看成是一颗完全二叉树 2 对于大顶堆 xff0c 确保每棵子树的根节点都是整个子树中的最大值 xff1b 这就保证了根节点是所有数据中的最大值 xff0c 但不保证所有数据有序 span class token comm
  • LED灯源控制

    1 LED五种调光控制方式详解 LED的发光原理同传统照明不同 xff0c 是靠P N结发光 xff0c 同功率的LED光源 xff0c 因其采用的芯片不同 xff0c 电流电压参数则不同 xff0c 故其内部布线结构和电路分布也不同 xf
  • LED驱动电路的分析

    文章目录 一 方案一 1 电路工作原理 2 组件选择 3 个人分析 二 方案二 在方案一的基础上改进 1 电路工作原理 2 个人分析 三 方案三 在方案一的基础上改进 1 电路工作原理 2 个人分析 参考连接 常见驱动电路的分析 一 方案一
  • linux基础操作之二

    文章目录 6 文件解压与打包1 概念讲解2 实战1 zip 压缩打包程序2 使用 unzip 命令解压缩 zip 文件3 tar 打包工具4 总结 7 文件系统操作与磁盘管理1 查看磁盘和目录的容量2 dd 命令简介3 使用 dd 命令创建
  • mmap的使用

    参考资料 mmap 函数 xff1a 原理与使用 含代码 mmap函数使用与实例详解 Linux系统编程 xff1a mmap使用技巧 mmap和普通文件读写的区别和比较 amp mmap的注意点 认真分析mmap xff1a 是什么 为什
  • LED高效恒流驱动电源的设计指导书

    参考链接 LED高效恒流驱动电源的设计指导书 LED灯驱动电源设计 LED恒流驱动电路 精 LED恒流驱动电路 led灯驱动电源电路图 led灯的驱动原理电路图方案详解 KIA MOS管 一 LED驱动电源原理 1 由于LED的光特性通常都
  • 恒流源驱动电路 随笔一

    方案一 参考论文 LED光源驱动电路研究 华科 硕士 08 06 采用恒流源控制的原因 1 LED的PN结的温度系数为负 温度升高时LED的势垒电势降低 由于这个特点 所以LED不能直接用电压源供电 必须采用限流措施 否则LED随着工作时温
  • 恒流源驱动电路 随笔二

    参考论文 LED的驱动电路研究 大理 硕士 07 06 三个简单方案 电荷泵驱动的典型电路 CAT3604是一个工作在1x 1 5x分数模式下的电荷泵 可调节每只LED白光管脚 xff08 共4只LED管脚 xff09 的电流 使背光的亮度
  • gcc编译c文件常用命令参数解释

    gcc编译c文件 gcc是常用来编译c语言程序的编译器 xff0c 了解它编译c语言的命令参数 xff0c 对c c 43 43 语言的学习是有一定好处的 gcc编译文件一步到位的命令格式 gcc main c o main exe 设置了
  • 恒流源驱动电路 随笔三

    参考论文一 LED蓝绿光黄疸光疗系统的研究与设计 天工 硕士 15 12 AMC7150是一种仅需 xff15 个外部零件的高功率LED驱动IC AMC7150内建P xff37 xff2d 和功率晶体管 xff0c 工作频率可达200kH
  • 光源系统厂商、结构

    参考论文 基于PWM的LED机器视觉光源技术的研究 哈工大 硕士 span class token number 2009 span fpga 前言 机器视觉系统包括 xff1a 照明 镜头 相机 图像采集卡 视觉处理器 led光源分为两大
  • LED驱动IC厂家

    厂家芯片类别 世微半导体 英飞凌Infineon 壹芯半导体科技 xff08 深圳 xff09 有限公司 欧司朗OSRAM xff1a 汽车照明 深圳天微电子有限公司 中铭电子 深圳市华芯光电有限公司 宁波欧特电子科技有限公司 芯片介绍 l
  • 2D/3D模板匹配

    2D 对象 正交视图 物体的组成部分之间的角度和距离可以改变 xff0c 不需要缩放 需要缩放 存在遮挡 杂乱或颜色 物体的特征是具有特定的纹理 xff0c 而不是清晰可见的轮廓 图像高度散焦 对象变化显著 期望物体轮廓的局部变形 xff0
  • linux基础操作之三

    文章目录 10 命令执行顺序控制与管道命令执行顺序的控制1 顺序执行多条命令2 有选择的执行命令 管道3 1 试用3 2 cut 命令 xff0c 打印每一行的某一字段3 3 grep 命令 xff0c 在文本中或 stdin 中查找匹配字
  • 2020华为软挑总结——baseline

    span class token macro property span class token directive keyword include span span class token string lt bits stdc 43
  • 2020华为软挑总结——复赛方案一code

    span class token macro property span class token directive keyword include span span class token string lt iostream gt s
  • 2020华为软挑总结——方案二code

    span class token macro property span class token directive keyword include span span class token string lt iostream gt s
  • 机器视觉照明技术与装置实验研究(论文纪要)

    参考文献 机器视觉照明技术与装置实验研究 中原 硕士 2016 有用 摘要 图片质量很大程度上是由目标周围的照明环境和目标物体表面材质 物体摆放位置所决定的 1 首先 xff0c 对照明系统主要技术进行了研究 研究内容包括光源的参数与选择
  • Affine Transformations(仿射变换)

    英文版原文链接 先修教程 xff1a Remapping 重映射 下一教程 xff1a Histogram Equalization 直方图均衡化 文章目录 结果目标原理什么是仿射变换 我们如何得到一个仿射变换 代码这个程序是做什么的 代码