小言_互联网的博客

OpenCV开发笔记(四十六):红胖子8分钟带你深入了解仿射变化(图文并茂+浅显易懂+程序源码)

431人阅读  评论(0)

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105691534
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)

OpenCV开发专栏(点击传送门)

上一篇:OpenCV开发笔记(四十五):红胖子8分钟带你深入了解重映射(图文并茂+浅显易懂+程序源码)

下一篇:OpenCV开发笔记(四十七):红胖子8分钟带你深入了解直方图(图文并茂+浅显易懂+程序源码)

 

前言

      红胖子来也!!!

      图像处理中的仿射,仿射其实原理与重映射类似,其可以理解为更高级的重映射变换。

 

相关博客

OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像

该文章中,也同样实现了部分简单重映射效果,使用的四个函数:

  • 旋转函数1:cv::transpose,直接对矩阵进行顺时钟旋转90°
  • 旋转函数2:cv::rotate,三个枚举可以旋转90°,180°,270°
  • 翻转函数:cv::flip,xy轴翻转
  • 缩放函数:cv::resize,缩放

OpenCV开发笔记(四十五):红胖子8分钟带你深入了解重映射(图文并茂+浅显易懂+程序源码)

 

Demo

 

仿射变换

概述

仿射变换(仿射映射)是指在几何中,一个响亮空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。

一个任意的仿射都能表示为乘以一个矩阵再加上一个向量(平移)的形式(注:重映射可以理解为是一种简单的仿射变换)。

  • 旋转:rotation,线性变换;
  • 平移:translation,向量加;
  • 缩放,scale,线性变换;

原理

      仿射是用矩阵表示变换的关系,通常使用的是2 x 3的矩阵来表示仿射变换。

      整个映射关系为:

      dst = src * A + B

其中:

      A为线性变换矩阵,B为向量加矩阵;

      对应的每个像素的变换关系,则是:

      dst(x,y) = src(x,y) * A + B

      下面上图解释仿射(三个点就是函数提供计算仿射矩阵需要我们输入的点):

与重映射原理区别

仿射变换的原理与重映射不同,重映射是直接对像素点的序号进行映射,可以做些拉长,特点像素着重等等(如哈哈镜),而仿射变换是对原矩阵的标准变换,有适合各自的场景。


  
  1. void warpAffine( InputArray src,
  2. OutputArray dst,
  3. InputArray M,
  4. Size dsize,
  5. int flags = INTER_LINEAR,
  6. int borderMode = BORDER_CONSTANT,
  7. const Scalar& borderValue = Scalar());
  • 参数一:InputArray类型的src,一般为cv::Mat;
  • 参数二:OutputArray类型的dst,目标图像。它的大小、类型与src相同。
  • 参数三:InputArray类型的M,即变换矩阵,大小为2 x 3。
  • 参数四:Size类型的size,表示输出图像的尺寸;
  • 参数五:int类型的interpolation,使用的插值方法;

  • 参数六:int类型的borderMode,边界处理方式;

  • 参数七:Scalar类型的borderValue,重映射后,离群点的背景,需要broderMode设置为BORDER_CONSTRANT时才有效。

计算二维三角变换矩阵函数原型


  
  1. Mat getAffineTransform( InputArray src,
  2. InputArray dst );
  • 参数一:InputArray类型的src,原来三个点的坐标;
  • 参数二:OutputArray类型的dst,映射后三个点的坐标;

计算二维旋转变换矩阵函数原型


  
  1. Mat getRotationMatrix2D( Point2f center,
  2. double angle,
  3. double scale );
  • 参数一:Point2f类型的center,输入的旋转中心点;
  • 参数二:double类型的angle,旋转的角度(逆时针旋转角度,非弧度);
  • 参数三:double类型的scale,缩放系数;

 

Demo源码


  
  1. void OpenCVManager::testAffineMap()
  2. {
  3. QString fileName1 =
  4. "E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
  5. cv::Mat srcMat = cv::imread(fileName1.toStdString());
  6. cv::Mat dstMat;
  7. int width = 400;
  8. int height = 300;
  9. cv::resize(srcMat, srcMat, cv::Size(width, height));
  10. cv::String windowName = _windowTitle.toStdString();
  11. cvui::init(windowName);
  12. cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2,
  13. srcMat.rows * 4),
  14. srcMat.type());
  15. while( true)
  16. {
  17. windowMat = cv::Scalar( 0, 0, 0);
  18. cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
  19. cv::Range(srcMat.cols * 0, srcMat.cols * 1));
  20. cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);
  21. // 第一种旋转180度
  22. {
  23. cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2,
  24. srcMat.rows / 2),
  25. 180.0f,
  26. 1.0f);
  27. dstMat = srcMat.clone();
  28. dstMat = cv::Scalar( 0, 0, 0);
  29. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  30. mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
  31. cv::Range(srcMat.cols * 1, srcMat.cols * 2));
  32. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  33. }
  34. // 第二种旋转45度,缩小1/2
  35. {
  36. cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2,
  37. srcMat.rows / 2),
  38. 45.0f,
  39. 0.5f);
  40. dstMat = srcMat.clone();
  41. dstMat = cv::Scalar( 0, 0, 0);
  42. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  43. mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
  44. cv::Range(srcMat.cols * 0, srcMat.cols * 1));
  45. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  46. }
  47. // 第三种旋转315度,缩小1/2
  48. {
  49. cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2,
  50. srcMat.rows / 2),
  51. 315.0f,
  52. 0.5f);
  53. dstMat = srcMat.clone();
  54. dstMat = cv::Scalar( 0, 0, 0);
  55. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  56. mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
  57. cv::Range(srcMat.cols * 1, srcMat.cols * 2));
  58. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  59. }
  60. // 第四种旋转135度,缩小1/2
  61. {
  62. cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2,
  63. srcMat.rows / 2),
  64. 135.0f,
  65. 0.5f);
  66. dstMat = srcMat.clone();
  67. dstMat = cv::Scalar( 0, 0, 0);
  68. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  69. mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
  70. cv::Range(srcMat.cols * 0, srcMat.cols * 1));
  71. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  72. }
  73. // 第五种旋转225度,缩小1/2
  74. {
  75. cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2,
  76. srcMat.rows / 2),
  77. 225.0f,
  78. 0.5f);
  79. dstMat = srcMat.clone();
  80. dstMat = cv::Scalar( 0, 0, 0);
  81. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  82. mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
  83. cv::Range(srcMat.cols * 1, srcMat.cols * 2));
  84. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  85. }
  86. // 第六种使用三角点进行仿射变换,沿着对角线翻转
  87. {
  88. cv::Point2f srcTraingle[ 3];
  89. cv::Point2f dstTraingle[ 3];
  90. srcTraingle[ 0] = cv::Point2f( 0, 0);
  91. srcTraingle[ 1] = cv::Point2f(srcMat.cols - 1, 0);
  92. srcTraingle[ 2] = cv::Point2f( 0, srcMat.rows - 1);
  93. dstTraingle[ 0] = cv::Point2f( 0, 0);
  94. dstTraingle[ 1] = cv::Point2f( 0, srcMat.rows - 1);
  95. dstTraingle[ 2] = cv::Point2f(srcMat.cols - 1, 0);
  96. cv::Mat M = cv::getAffineTransform(srcTraingle, dstTraingle);
  97. dstMat = srcMat.clone();
  98. dstMat = cv::Scalar( 0, 0, 0);
  99. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  100. mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
  101. cv::Range(srcMat.cols * 0, srcMat.cols * 1));
  102. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  103. }
  104. // 第七种使用三角点进行仿射变换
  105. {
  106. cv::Point2f srcTraingle[ 3];
  107. cv::Point2f dstTraingle[ 3];
  108. srcTraingle[ 0] = cv::Point2f( 0, 0);
  109. srcTraingle[ 1] = cv::Point2f(srcMat.cols - 1, 0);
  110. srcTraingle[ 2] = cv::Point2f( 0, srcMat.rows - 1);
  111. dstTraingle[ 0] = cv::Point2f(srcMat.cols / 4, srcMat.rows / 4);
  112. dstTraingle[ 1] = cv::Point2f(srcMat.cols / 4 * 3, srcMat.rows / 4 );
  113. dstTraingle[ 2] = cv::Point2f(srcMat.cols / 2, srcMat.rows - 1);
  114. cv::Mat M = cv::getAffineTransform(srcTraingle, dstTraingle);
  115. dstMat = srcMat.clone();
  116. dstMat = cv::Scalar( 0, 0, 0);
  117. cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
  118. mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
  119. cv::Range(srcMat.cols * 1, srcMat.cols * 2));
  120. cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
  121. }
  122. // 更新
  123. cvui::update();
  124. // 显示
  125. cv::imshow(windowName, windowMat);
  126. // esc键退出
  127. if(cv::waitKey( 25) == 27)
  128. {
  129. break;
  130. }
  131. }
  132. }

 

工程模板:对应版本号v1.41.0

      对应版本号v1.41.0

 

上一篇:OpenCV开发笔记(四十五):红胖子8分钟带你深入了解重映射(图文并茂+浅显易懂+程序源码)

下一篇:OpenCV开发笔记(四十七):红胖子8分钟带你深入了解直方图(图文并茂+浅显易懂+程序源码)


原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105691534


转载:https://blog.csdn.net/qq21497936/article/details/105691534
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场