【OpenCV】OpenCV基础教程(2)—— 几何变换

2. 几何变换

2.1 仿射变换

2.1.1 仿射变换矩阵

仿射变换矩阵:
A = [ a 11 a 12 a 13 a 21 a 22 a 23 0 0 1 ] \mathbf{A}=\left[ \begin{matrix} {{a}_{11}} & {{a}_{12}} & {{a}_{13}} \\ {{a}_{21}} & {{a}_{22}} & {{a}_{23}} \\ 0 & 0 & 1 \\\end{matrix} \right] A=a11a210a12a220a13a231
基本的仿射变换类型:平移、缩放、旋转。

2.1.2 计算仿射矩阵
1. 方程法

仿射变换矩阵有六个未知数,所以只需要三组对应位置坐标,构造出由六个方程组成的方程组即可解六个未知数。

CV_EXPORTS Mat cv::getAffineTransform(const Point2f src[], const Point2f dst[])
//原位置坐标
Point2f src[] = {Point2f(0,0), Point2f(200,0), Point2f(0,200)};
//经过仿射变换后的坐标
Point2f dst[] = {Point2f(0,0), Point2f(200,0), Point2f(0,200)};
//计算仿射矩阵
Mat A = getAffineTransform(src, dst);	//返回值是2行3列的矩阵,指的是仿射变换矩阵的前两行
/*
[1, 0, 0;
 0, 1, 0]
*/

注意:返回的数据类型是CV_64F而不是CV_32F

2. 矩阵法

先缩放 再平移

假设对空间坐标先等比例缩放0.5倍,然后在水平方向上平移100,在垂直方向上平移200,计算该仿射变换矩阵。

//缩放矩阵
Mat s = (Mat_<float>(3,3)<<0.5,0,0, 0,0.5,0, 0,0,1);
//平移矩阵
Mat t = (Mat_<float>(3,3)<<1,0,100, 0,1,200, 0,0,1);
//矩阵相乘
Mat A = t * s;

先缩放 再旋转

假设对空间坐标先等比例缩放0.5倍,然后以坐标点(40,50)为中心逆时针旋转30°,计算该仿射变换矩阵。

cv::Mat cv::getRotationMatrix2D(cv::Point2f center, double angle, double scale)

center:变换中心点的坐标

angle:逆时针旋转的角度

scale:等比例缩放的系数

Mat A = getRotationMatrix2D(Point(40,50),30,0.5);	//返回值是2行3列的矩阵,指的是仿射变换矩阵的前两行
/*
[0.4330127018922194, 0.25, 10.17949192431122;
 -0.25, 0.4330127018922194, 38.34936490538903]
*/

注意:返回的数据类型是CV_64F而不是CV_32F

2.1.3 插值算法

插值的正确做法是,反过来考虑,我们的目标是设置 f O {{f}_{\mathbf{O}}} fO在第一象限的任意整数坐标 ( x ^ , y ^ ) (\hat{x},\hat{y}) (x^,y^)处的值,那么首先计算出在 x o y xoy xoy平面中哪一个坐标 ( x , y ) (x,y) (x,y)经变换后为 ( x ^ , y ^ ) (\hat{x},\hat{y}) (x^,y^),可通过单应性矩阵 H H H的逆进行计算,即:
[ x y 1 ] = H − 1 [ x ^ y ^ 1 ] \left[ \begin{matrix} x \\ y \\ 1 \\ \end{matrix} \right]={{H}^{-1}}\left[ \begin{matrix} {\hat{x}} \\ {\hat{y}} \\ 1 \\ \end{matrix} \right] xy1=H1x^y^1

1. 最近邻插值

最近邻插值就是从 ( x , y ) (x,y) (x,y)的四个相邻整数坐标中找到离它最近的一个,假设为 ( x ^ , y ^ ) (\hat{x},\hat{y}) (x^,y^),然后令 f I ( x , y ) = f I ( x ^ , y ^ ) {{f}_{\mathbf{I}}}(x,y)={{f}_{\mathbf{I}}}(\hat{x},\hat{y}) fI(x,y)=fI(x^,y^)

使用最近邻插值方法完成图像几何变换,输出图像会出现锯齿状外观,对图像放大处理的效果会更明显。

2. 双线性插值

先进行两次水平方向上的插值,在进行垂直方向上的插值。

image-20211012215756063

这里直接给出结果:
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲ & {{f}_{\mat…

3. 图像缩放
void cv::resize(cv::InputArray src, cv::OutputArray dst, cv::Size dsize, double fx = (0.0), double fy = (0.0), int interpolation = 1)

src:输入图像矩阵

dst:输出图像矩阵

dsize:二元元组(宽, 高),输出图像的大小

fx:在水平方向上的缩放比例,默认为0

fy:在垂直方向上的缩放比例,默认为0

interplotation:插值法。INTE_NEAREST、INTE_LINEAR(默认)等

resize函数有以下两种使用方式:

//将图像缩小到0.5倍
resize(I, dst2, Size(), 0.5, 0.5);
resize(I, dst2, Size(I.cols/2, I.rows/2), 0, 0);
4. 图像旋转
void cv::rotate(cv::InputArray src, cv::OutputArray dst, int rotateCode)

src:输入图像矩阵

dst:输出图像矩阵

rotateCode:ROTATE_90_CLOCKWISE:顺时针旋转90°;ROTATE_180:顺时针旋转180°;ROTATE_90_COUNTERCLOCKWISE:顺时针旋转270°

2.1.4 投影变换
cv::Mat cv::findHomography(cv::InputArray srcPoints, cv::InputArray dstPoints, int method = 0, double ransacReprojThreshold = (3.0), cv::OutputArray mask = noArray(), int maxIters = 2000, double confidence = (0.9949999999999999956))
cv::Mat cv::getPerspectiveTransform(cv::InputArray src, cv::InputArray dst)

getPerspectiveTransform用的是SVD分解,getPerspectiveTransform只会拿前4个点去计算,getPerspectiveTransform比较简单粗暴。
findHomography则会拿一堆点(>=4)去计算(其是不断从一堆点中重复拿出4个点去计算出一个结果,再采用一些优化算法RANSAC/LMEDS去筛选出最优解)。

getPerspectiveTransform有两种用法,第一种用法如下:

Point2f src[] = {Point2f(0,0), Point2f(200,0), Point2f(0,200), Point2f(200,200)};
Point2f dst[] = {Point2f(100,20), Point2f(200,20), Point2f(50,70), Point2f(250,70)};
Mat P = getPerspectiveTransform(src, dst);

注意:返回的投影矩阵的数据类型为CV_64F

第二种方式是将原位置坐标和对应的变换后的位置坐标分别保存在4×2的Mat中,每一行代表一个坐标,代码如下:

Mat src = (Mat_<float>(4,2) << 0, 0, 200, 0, 0, 200, 200, 200);
Mat dst = (Mat_<float>(4,2) << 100, 20, 200, 20, 50, 70, 250, 70);
Mat P = getPerspectiveTransform(src, dst);

2.2 极坐标变换

先略,时间多再回来补

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quentin_HIT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值