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](见本文示例代码)。

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: OpenCV Python中的仿射变换是一种图像处理技术,它可以对图像进行旋转、缩放、平移和扭曲等变换操作,从而实现图像的形状变换和位置变换。在实际应用中,仿射变换常用于图像校正、图像配准、图像拼接等领域。通过OpenCV Python中的仿射变换函数,我们可以轻松地实现图像的变换操作,从而满足不同应用场景的需求。 ### 回答2: OpenCV是一个开源的计算机视觉库,提供了许多用于图像处理和计算机视觉任务的函数和工具,其中包括旋转、缩放、仿射变换等操作。在Python程序中使用OpenCV仿射变换功能,可以轻松地对图像进行平移、旋转、缩放和扭曲等操作。 仿射变换是一种线性变换,可以通过线性代数的方法计算。可以将任何形状的物体固定在一个二维平面上并按照一定的比例和角度旋转或缩放,然后将其投影到另一个平面上。在使用OpenCV进行仿射变换时,需要首先定义一个变换矩阵,然后将其应用到图像上。 在OpenCV中,可通过函数cv2.getAffineTransform() 获得仿射矩阵,该函数需要输入源图像上的三个点和目标图像上的三个点。然后,可以通过函数cv2.warpAffine() 将变换矩阵应用到图像上。该函数还可以用于旋转、镜像、平移和缩放等图像变换。需要注意的是,如果变换后的图像大小与原图不同,需要进行适当的裁剪。 实现OpenCV仿射变换通常需要以下步骤: 1. 定义源图像上和目标图像上的三个点; 2. 调用函数cv2.getAffineTransform() 获得变换矩阵; 3. 调用函数cv2.warpAffine() 将变换矩阵应用到图像上; 4. 如果需要,进行图像裁剪。 需要注意的是,在进行仿射变换时,变换前和变换后的图像像素位置之间是线性关系,因此,变换后的图像像素值需要通过插值方法计算得出。在OpenCV中,可选择使用最近邻插值、双线性插值或双三次插值来进行插值计算。 在Python中使用OpenCV仿射变换功能可以应用于各种场景,例如图像矫正、景深合成、数字识别、人脸识别等任务,具有极高的实用价值。 ### 回答3: OpenCV 是一个开源的计算机视觉和机器学习库,提供了许多强大的工具和算法来协助计算机实现如人类一样的视觉功能。其中,仿射变换OpenCV 中常用的一种图像几何变换方法,用于实现图像的缩放、平移、旋转和投影等功能。 在 OpenCV 中,可以使用 cv2.warpAffine() 函数实现仿射变换。这个函数接收三个参数:原始图像、变换矩阵和输出图像的尺寸。其中,变换矩阵是一个 2x3 的矩阵,包括平移、旋转和缩放等变换操作的参数。根据需要,可以通过调整变换矩阵的值来完成不同的变换操作。 现在,假设我们要对一张原始图片进行仿射变换,将其旋转 45 度并向右平移 100 像素。首先,需要使用 OpenCV 加载该图片: ``` import cv2 img = cv2.imread('original.jpg') ``` 然后,我们需要定义一个变换矩阵来实现旋转和平移操作,可以通过 cv2.getRotationMatrix2D() 函数来生成变换矩阵。该函数接收三个参数:旋转中心、旋转角度和缩放倍数。在本例中,旋转中心为图像中心,旋转角度为 45 度,缩放倍数为 1: ``` rows, cols = img.shape[0:2] center = (cols/2, rows/2) angle = 45 scale = 1 M = cv2.getRotationMatrix2D(center, angle, scale) ``` 接下来,我们需要根据需要将图片向右平移,可以直接操作变换矩阵的第三列: ``` tx = 100 M[0, 2] += tx ``` 最后,我们可以使用 cv2.warpAffine() 函数对图片进行仿射变换,输出处理后的图片: ``` dst = cv2.warpAffine(img, M, (cols, rows)) cv2.imshow('result', dst) cv2.waitKey(0) ``` 在本例中,输出的图片将会是原始图片旋转 45 度并向右平移 100 像素后的结果。 总之,opencv python 仿射变换提供了丰富的图像几何变换方法,可以通过变换矩阵来实现不同的变换操作。它是计算机视觉和机器学习领域中非常有用的工具之一,可以协助研究人员和开发者实现真正意义上的计算机视觉应用和智能化系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Humbunklung

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

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

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

打赏作者

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

抵扣说明:

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

余额充值