OpenCV仿射变换实现图像扭曲与旋转

目录

1. 仿射变换

2. 仿射变换的求解

3. 代码实现

3.1 图像扭曲

3.2 图像旋转

参考内容


1. 仿射变换

仿射变换是一种可以表达为乘以一个矩阵(线性变换)再加上一个向量(平移)的变换。在几何中,就是将一个向量空间进行一次线性变化并接上一个平移。

因此我们可以用仿射变化表达如下内容:

  1. 旋转Rotations(线性变换,linear transformation);
  2. 平移Translations(矢量加,vector addition);
  3. 缩放操作Scale operations(线性变换)。

由此可见,在图像处理当中,仿射变换本质上反映了两个图像之间的关系。

我们通常使用2×3矩阵来表示仿射变换。

对于“乘以一个矩阵”的线性变换,我们引入矩阵A:

A=\left[\begin{matrix}a_{00}&a_{01}\\a_{10}&a_{11}\\\end{matrix}\right]

对于加法部分(平移),我们引入矩阵B:

B=\left[\begin{matrix}b_{00}\\b_{10}\\\end{matrix}\right]

设待转换的二维列向量为X,转换后的向量为T,则:

X=\left[\begin{matrix}x\\y\\\end{matrix}\right]

T=AX+B=A\cdot\left[\begin{matrix}x\\y\\\end{matrix}\right]+B

考虑齐次坐标和齐次矩阵更易于进行仿射几何变换,令:

M=[\begin{matrix}A&B\\\end{matrix}]=\begin{bmatrix} a_{00} & a_{01} & b_{00}\\ a_{10} & a_{11} & b_{10} \end{bmatrix}

二维向量X视作一个点,其齐次坐标表示为这样的列向量:

\left[\begin{matrix}x\\y\\1\\\end{matrix}\right]

这样,我们可以借助齐次坐标,把平移变量也通过一个矩阵表示,则有:

T=M\cdot\left[\begin{matrix}x\\y\\1\\\end{matrix}\right]

可见矩阵M就是我们所需要的仿射变换矩阵。

2. 仿射变换的求解

参考内容通过几何方式(三角形三个顶点的映射)描述仿射变换的求解过程,我们也可以用代数知识表达,对于不共线的三点,令:

T=\begin{bmatrix} {x}'\\ {y}' \end{bmatrix} =\begin{bmatrix} {x_0'} & {x_1'} & {x_2'} \\ {y_0'} & {y_1'} & {y_2'} \end{bmatrix}

X=\begin{bmatrix} {x}\\ {y} \end{bmatrix} =\begin{bmatrix} {x_0} & {x_1} & {x_2} \\ {y_0} & {y_1} & {y_2} \end{bmatrix}

方程

T=M\left[\begin{matrix}X\\1\\\end{matrix}\right]=M\left[\begin{matrix}x\\y\\1\\\end{matrix}\right]

其方程组形式为:

\left\{\begin{matrix} a_{00}x_0+a_{01}y_0+b_{00}={x_0'} \\ a_{10}x_0+a_{11}y_0+b_{10}={y_0'} \\ a_{00}x_1+a_{01}y_1+b_{00}={x_1'} \\ a_{10}x_1+a_{11}y_1+b_{10}={y_1'} \\ a_{00}x_2+a_{01}y_2+b_{00}={x_2'} \\ a_{10}x_2+a_{11}y_2+b_{10}={y_2'} \end{matrix}\right.

有唯一解,从而可以求出仿射矩阵M。

在OpenCV中,我们可以通过cv::getAffineTransform函数求解仿射矩阵或cv::getRotationMatrix2D,求解二维旋转矩阵。

Mat cv::getAffineTransform

(

InputArray

src,

InputArray

dst 

)

Python:

cv.getAffineTransform(

src, dst

) ->

retval

getRotationMatrix2D()

Mat cv::getRotationMatrix2D

(

Point2f

center,

double 

angle,

double 

scale 

)

inline

Python:

cv.getRotationMatrix2D(

center, angle, scale

) ->

retval

3. 代码实现

3.1 图像扭曲

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>using namespace cv;int main()
{// 读取图像Mat src = imread("park.jpg");if (src.empty()){std::cout << "Could not open or find the image!\n" << std::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.55f, src.rows * 0.25f);dstTri[2] = Point2f(src.cols * 0.35f, src.rows * 0.7f);// 求解仿射矩阵Mat warp_mat = getAffineTransform(srcTri, dstTri);// 求解扭曲后的图像Mat warp_dst;warpAffine(src, warp_dst, warp_mat, src.size());imshow("Warped Image", warp_dst);waitKey(0);return 0;
}
# 图像扭曲
import cv2
import numpy as np# 读取图像
img = cv2.imread('park.jpg')# 图像扭曲
(rows, cols) = img.shape[:2]
srcTri = np.array( [[0, 0], [img.shape[1] - 1, 0], [0, img.shape[0] - 1]] ).astype(np.float32)
dstTri = np.array( [[0, img.shape[0]*0.33], [img.shape[1]*0.55, img.shape[0]*0.25], [img.shape[1]*0.35, img.shape[0]*0.7]] ).astype(np.float32)
M = cv2.getAffineTransform(srcTri, dstTri)
warped_img = cv2.warpAffine(img, M, (cols, rows))# 显示旋转后的图像 
cv2.imshow('Warped Image', warped_img)# 等待用户输入并关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2 图像旋转

#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>using namespace cv;int main()
{// 读取图像Mat src = imread("park.jpg");if (src.empty()){std::cout << "Could not open or find the image!\n" << std::endl;return -1;}// 设置旋转中心、旋转角度和缩放比例Point center = Point(src.cols / 2, src.rows / 2);double angle = 35;double scale = 0.5;// 获取旋转矩阵Mat rot_mat = getRotationMatrix2D(center, angle, scale);// 旋转后的图像Mat rotated_dst;warpAffine(src, rotated_dst, rot_mat, src.size());    // 显示图像imshow("Rotated Image", rotated_dst);waitKey(0);return 0;
}
# 图像旋转
import cv2# 读取图像
img = cv2.imread('park.jpg')# 旋转图像
(rows, cols) = img.shape[:2]
M = cv2.getRotationMatrix2D((cols/2, rows/2), 35, 0.5)
rotated_img = cv2.warpAffine(img, M, (cols, rows))# 显示旋转后的图像 
cv2.imshow('Rotated Image', rotated_img)# 等待用户输入并关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()

参考内容

OpenCV: Affine Transformations

注:OpenCV这个文档的示例代码中,C++代码和Python代码并不匹配,Python代码中的dstTri第一个点的y坐标,shape[1]应为shape[0](见本文示例代码)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/389451.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hive环境搭建(Mysql数据库)

【实验目的】 1) 了解hive的作用 2) 熟练hive的配置过程&#xff08;Mysql数据库&#xff09; 【实验原理】 Hive工具中默认使用的是derby数据库&#xff0c;该数据库使用简单&#xff0c;操作灵活&#xff0c;但是存在一定的局限性&#xff0c;hive支持使用第三方数据库&…

Umi-OCR:功能强大且易于使用的本地照片识别软件

Umi-OCR是一款开源且免费的离线OCR&#xff08;光学字符识别&#xff09;软件&#xff0c;可让您轻松从照片中提取文本。它支持多种语言&#xff0c;并具有许多其他功能使其成为照片识别任务的绝佳选择。 Umi-OCR的优势 离线操作&#xff1a; Umi-OCR无需互联网连接即可工作&…

html+css 实现文字滚动的按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

手摸手教你前端和后端是如何实现导出 Excel 的?

前言 大家好呀&#xff0c;我是雪荷。在上篇文章&#xff08;EasyExcel 初使用—— Java 实现多种写入 Excel 功能-CSDN博客&#xff09;中给大家介绍了 Java 是如何写入 Excel 的&#xff0c;那么这篇算是对上篇文章的拓展&#xff0c;主要介绍前端和后端分别是如何导出数据至…

代码随想录训练营 Day18打卡 二叉树 part06 530. 二叉搜索树的最小绝对差 501. 二叉搜索树中的众数 236. 二叉树的最近公共祖先

代码随想录训练营 Day18打卡 二叉树 part06 一、 力扣530. 二叉搜索树的最小绝对差 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 &#xff1a; 输入&#xff1a; …

spring boot + vue3 接入钉钉实现扫码登录

1&#xff1a;准备工作 1.1&#xff1a;进入钉钉开放平台创建开发者应用。应用创建和类型介绍&#xff0c;参考下方。 应用类型介绍 - 钉钉开放平台 (dingtalk.com) 应用能力介绍 - 钉钉开放平台 (dingtalk.com) 扫码登录第三方网站 - 钉钉开放平台 (dingtalk.com) 1.2&…

KaiwuDB 产品总监李月飞:让中国物联网用上放心的数据库产品

​2024年7月17日&#xff0c;KaiwuDB 产品总监李月飞受邀于 2024 可信数据库发展大会“能源与政务数据库应用创新”分论坛发表演讲。以下是李月飞主题演讲《深耕数据良田&#xff0c;KaiwuDB 洞见能源产业数字新生力》精华实录。 数据&#xff0c;给能源变革带来新的可能 众所…

TypeScript 简介

文档 typeScript官网中文文档&#xff1a;https://www.tslang.cn/index.html中文文档(简洁点)&#xff1a;https://typescript.bootcss.comMDN 前言 JavaScript 引入编程社区已有 20 多年&#xff0c;如今已成为有史以来使用最广泛的跨平台语言之一。JavaScript 最初是一种用…

SSL VPN详细概述

为什么会出现SSL VPN呢&#xff1f;在这之前不是有IPSEC VPN吗&#xff1f; 通过这两个问题我们可以发现多半是IPSEC VPN在某些方面肯定有所欠缺&#xff0c;所以后面在出现了SSL VPN。 之前说过根据组网方式划分&#xff0c;可以分为 client to LAN 和 LAN to LAN 两种 而…

CTF学习笔记汇总(非常详细)零基础入门到精通,收藏这一篇就够了

CTF学习笔记汇总 Part.01 Web 01 SSRF 主要攻击方式如下&#xff1a; 01 对外网、服务器所在内网、本地进行端口扫描&#xff0c;获取一些服务的banner信息。 02 攻击运行在内网或本地的应用程序。 03 对内网Web应用进行指纹识别&#xff0c;识别企业内部的资产信息。 …

深入分析 Android ContentProvider (十二)

文章目录 深入分析 Android ContentProvider (十二)Android 中 ContentProvider 的系统代码分析&#xff08;续&#xff09;1. ContentProvider 的内部实现机制1.1. ContentProvider 的创建与生命周期管理1.2. ContentProvider 的数据访问与处理1.3. ContentProvider 的权限管理…

Go语言---sync.WaitGroup

在Go语言中&#xff0c;给我们提供了用于线程同步的sync.WaitGroup&#xff0c;简单来讲&#xff0c;WaitGroup就是指等待一组&#xff0c;等待一个系列执行完成后才会继续向下执行。 WaitGroup数据结构 type WaitGroup struct {noCopy noCopystate atomic.Uint64 // 高 32 b…

无人驾驶的未来:AI如何重塑我们的出行世界

无人驾驶汽车&#xff0c;作为人工智能&#xff08;AI&#xff09;技术的集大成者&#xff0c;正以前所未有的速度改变着我们的出行方式。从机器学习到计算机视觉&#xff0c;再到人工智能生成内容&#xff08;AIGC&#xff09;&#xff0c;AI技术的每一次进步都在为无人驾驶汽…

华为手机连接电脑后电脑无反应、检测不到设备的解决方法

本文介绍华为手机与任意品牌电脑连接时&#xff0c;出现连接后电脑无反应、检测不到手机连接情况的解决方法。 最近&#xff0c;因为手机的存储空间愈发紧缺&#xff0c;所以希望在非华为电脑中&#xff0c;将华为手机内的照片、视频等大文件备份、整理一下。因此&#xff0c;需…

公司里的IT是什么?

公司里的IT是什么&#xff1f; 文章目录 公司里的IT是什么&#xff1f;1、公司里的IT2、IT技术3、IT行业4、IT行业常见证书 如果对你有帮助&#xff0c;就点赞收藏把&#xff01;(&#xff61;&#xff65;ω&#xff65;&#xff61;)&#xff89;♡ 前段时间&#xff0c;在公…

《Windows API每日一练》24.1 WinSock简介

本节将逐一介绍WinSock的主要特性和组件&#xff0c;套接字、WinSock动态库的使用。 本节必须掌握的知识点&#xff1a; Windows Socket接口简介 Windows Socket接口的使用 第178练&#xff1a;网络时间校验 24.1.1 Windows Socket接口简介 ■以下是WinSock的主要特性和组件…

实时转换,轻松编辑:2024年高效语音转文字解决方案

现在生活节奏越来越快了&#xff0c;很多时候一场会议内容的信息量就会呈几何式增长。用笔来记录肯定来不及&#xff0c;那还有一个方法就是录音或者录像。录制完成后我们可以使用语音转文字来快速获取会议内容是不是就方便了很多。 1.365在线转文字 链接传送&#xff1a;ww…

华为云依赖引入错误

问题&#xff1a;记录一次项目加载华为云依赖错误&#xff0c;如下&#xff1a; 错误信息&#xff1a;Could not find artifact com.huawei.storage:esdk-obs-java:pom:3.1.2.1 in bintray-qcloud-maven-repo (https://dl.bintray.com/qcloud/maven-repo/) 找到本地仓库&#…

【practise】string_atoi

今天来分享一道比较平常的练习题&#xff0c;说实话我自己写了半天&#xff0c;自己写的很烂最后还是看的答案… 1.题目概要 题目链接&#xff1a;LINK 2.题目难点 这个题目有两个难点&#xff0c;如下&#xff1a; 拿到了全部都是数字字符的字符串&#xff0c;怎么将这个…

从技术角度解读【与辉同行】文案(一)

视频文字内容 标题&#xff1a;走晋.山西 内容&#xff1a;将一段岁月熔成佳酿&#xff0c;三晋儿女荡气回肠。捧一把黄土架起火柴&#xff0c;华夏大地照亮火光。五千年黄土风云&#xff0c;历代千秋根固魂盈。三万顷汾河烟雨&#xff0c;唐风宋韵人杰地灵。当先辈手持石器抛挖…