OpenCV的仿射变换

目标

在本教程中,您将学习如何:

理论

什么是仿射变换?

  1. 一种可以用矩阵乘法(线性变换)后跟向量加法(平移)的形式表示的变换。

  2. 综上所述,我们可以使用仿射变换来表示:

    1. 旋转(线性变换)
    2. 翻译(向量添加)
    3. 缩放操作(线性变换)

    您可以看到,从本质上讲,仿射变换表示两个图像之间的关系。

  3. 表示仿射变换的常用方法是使用 \(2 \times 3\) 矩阵。

    [ 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} ]

    [ 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} ]

    考虑到我们想通过使用 \(A\) 和 \(B\) 来转换二维向量 \(X = \begin{bmatrix}x \ y\end{bmatrix}\),我们可以用以下方法做同样的事情:

    \(T = A \cdot \begin{bmatrix}x \ y\end{bmatrix} + B\) 或 \(T = M \cdot [x, y, 1]^{T}\)

    [T = \begin{bmatrix} a_{00}x + a_{01}y + b_{00} \ a_{10}x + a_{11}y + b_{10} \end{bmatrix}]

我们如何获得仿射变换?

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

    1. 我们知道\(X\)和T,我们也知道它们是相关的。那么我们的任务是找到\(M\)
    2. 我们知道 \(M\) 和 \(X\)。要获得 \(T\),我们只需要应用 \(T = M \cdot X\)。我们对 \(M\) 的信息可能是显式的(即具有 2×3 矩阵),也可以是点之间的几何关系。
  2. 让我们用更好的方式解释这一点(b)。由于 \(M\) 关联 2 个图像,我们可以分析它关联两个图像中的三个点的最简单情况。请看下图:

    Warp_Affine_Tutorial_Theory_0.jpg

    点 1、2 和 3(在图 1 中形成一个三角形)映射到图像 2 中,仍然形成一个三角形,但现在它们已经发生了众所周知的变化。如果我们找到这 3 个点的仿射变换(您可以根据需要选择它们),那么我们可以将这种找到的关系应用于图像中的所有像素。

法典 C++爪哇岛蟒

  • 这个程序是做什么的?

    • 加载图像
    • 对图像应用仿射变换。此变换是从三点之间的关系中获得的。为此,我们使用函数 cv::warpAffine
    • 在变换后对图像应用旋转。此旋转相对于图像中心
    • 等待,直到用户退出程序
  • 本教程的代码如下所示。您也可以在此处下载

    #include“opencv2/imgcodecs.hpp

    #include “opencv2/highgui.hpp

    #include“opencv2/imgproc.hpp

    #include < iostream>

    使用命名空间 CV;

    使用命名空间 std;

    int main( int argc, char** argv )

    {

    CommandLineParser 解析器( argc, argv, “{@input |莉娜.jpg |输入图像}” );

    Mat src = imreadsamples::findFile( parser.get[>( “@input” ) ) );

    ​ if( src.() )

    ​ {

    cout << “无法打开或找到图像!”<<结束;

    cout << “Usage: ” << argv[0] << “ ” << endl;

    ​ 返回 -1;

    ​ }

    Point2f srcTri[3];

    srcTri[0] = 点2f( 0.f, 0.f );

    srcTri[1] = Point2f( src.cols - 1.f, 0.f );

    srcTri[2] = Point2f( 0.f, src. - 1.f );

    Point2f dstTri[3];

    dstTri[0] = Point2f( 0.f, src.行*0.33F);

    dstTri[1] = Point2f( src.COLS*0.85F,SRC。*0.25F);

    dstTri[2] = Point2f( src.COLS*0.15F,src。行*0.7f );

    Mat warp_mat = getAffineTransform( srcTri, dstTri );

    子 warp_dst = Mat::zeros( src.,src。科尔斯,SRC。类型() );

    warpAffine( src, warp_dst, warp_mat, warp_dst.大小() );

    中心 = Point( warp_dst.Cols/2,warp_dst。/2 );

    ​ 双角 = -50.0;

    ​ 双刻度 = 0.6;

    Mat rot_mat = getRotationMatrix2D( center, angle, scale );

    子warp_rotate_dst;

    warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.大小() );

    imshow( “源图像”, src );

    imshow( “翘曲”, warp_dst );

    imshow( “翘曲 + 旋转”, warp_rotate_dst );

    等待键();

    ​ 返回 0;

    }

解释 C++爪哇岛蟒

  • 加载图像:

CommandLineParser 解析器( argc, argv, “{@input |莉娜.jpg |输入图像}” );

Mat src = imreadsamples::findFile( parser.get<String>( “@input” ) ) );

​ 如果( src.empty() )

​ {

cout << “无法打开或找到图像!”<<结束;

cout << “Usage: ” << argv[0] << “ ” << endl;

​ 返回 -1;

​ }

  • **仿射变换:**正如我们在上面几行中解释的那样,我们需要两组 3 点来推导仿射变换关系。看一看:

Point2f srcTri[3];

srcTri[0] = 点2f( 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.cols0.85f, src.rows0.25f );

dstTri[2] = Point2f( src.cols0.15f, src.rows0.7f );

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

Mat warp_mat = getAffineTransform( srcTri, dstTri );

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

  • 然后,我们将刚刚找到的仿射变换应用于 src 图像

Mat warp_dst = Mat::zeros( src.rows, src.cols, src.type() );

warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

使用以下参数:

  • src:输入图像
  • warp_dst:输出图像
  • warp_mat:仿射变换
  • warp_dst.size():输出图像的所需大小

我们刚刚得到了我们的第一个转换图像!我们将一比特地显示它。在此之前,我们还想旋转它…

  • **旋转:**要旋转图像,我们需要知道两件事:

    1. 图像将相对于其旋转的中心
    2. 要旋转的角度。在 OpenCV 中,正角度是逆时针方向
    3. *自选:*比例因子

    我们使用以下代码片段定义这些参数:

中心 = Point( warp_dst.cols/2, warp_dst.rows/2 );

​ 双角 = -50.0;

​ 双刻度 = 0.6;

  • 我们使用 OpenCV 函数 cv::getRotationMatrix2D 生成旋转矩阵,该函数返回一个 2 \times 3 矩阵(在本例中为 rot_mat2×3)

Mat rot_mat = getRotationMatrix2D( center, angle, scale );

  • 现在,我们将找到的旋转应用于上一个变换的输出:

垫子warp_rotate_dst;

warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );

  • 最后,我们在两个窗口中显示结果以及原始图像以进行良好的测量:

imshow( “源图像”, src );

imshow( “翘曲”, warp_dst );

imshow( “翘曲 + 旋转”, warp_rotate_dst );

  • 我们只需要等到用户退出程序

等待键();

结果

  • 编译完上面的代码后,我们可以给它一个图像的路径作为参数。例如,对于这样的图片:

    Warp_Affine_Tutorial_Original_Image.jpg

    应用第一个仿射变换后,我们得到:

    Warp_Affine_Tutorial_Result_Warp.jpg

    最后,在应用负旋转(记住负意味着顺时针)和比例因子后,我们得到:

    Warp_Affine_Tutorial_Result_Warp_Rotate.jpg

    在线教程

  • 麻省理工学院人工智能视频教程 – 麻省理工人工智能课程

  • 人工智能入门 – 人工智能基础学习。Peter Norvig举办的课程

  • EdX 人工智能 – 此课程讲授人工智能计算机系统设计的基本概念和技术。

  • 人工智能中的计划 – 计划是人工智能系统的基础部分之一。在这个课程中,你将会学习到让机器人执行一系列动作所需要的基本算法。

  • 机器人人工智能 – 这个课程将会教授你实现人工智能的基本方法,包括:概率推算,计划和搜索,本地化,跟踪和控制,全部都是围绕有关机器人设计。

  • 机器学习 – 有指导和无指导情况下的基本机器学习算法

  • 机器学习中的神经网络 – 智能神经网络上的算法和实践经验

  • 斯坦福统计学习
    有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

请添加图片描述

人工智能书籍

第一阶段:零基础入门(3-6个月)

新手应首先通过少而精的学习,看到全景图,建立大局观。 通过完成小实验,建立信心,才能避免“从入门到放弃”的尴尬。因此,第一阶段只推荐4本最必要的书(而且这些书到了第二、三阶段也能继续用),入门以后,在后续学习中再“哪里不会补哪里”即可。

第二阶段:基础进阶(3-6个月)

熟读《机器学习算法的数学解析与Python实现》并动手实践后,你已经对机器学习有了基本的了解,不再是小白了。这时可以开始触类旁通,学习热门技术,加强实践水平。在深入学习的同时,也可以探索自己感兴趣的方向,为求职面试打好基础。

第三阶段:工作应用

这一阶段你已经不再需要引导,只需要一些推荐书目。如果你从入门时就确认了未来的工作方向,可以在第二阶段就提前阅读相关入门书籍(对应“商业落地五大方向”中的前两本),然后再“哪里不会补哪里”。

有需要的小伙伴,可以点击下方链接免费领取或者V扫描下方二维码免费领取🆓

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值