youcans 的 OpenCV 学习课—5.图像的几何变换

本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战。

几何变换是指对图像的位置、大小、形状、投影进行变换,是将图像从原始平面投影到新的视平面。OpenCV 中的图像以多维数组描述,几何变换本质上是将一个多维数组通过映射关系求得另一个多维数组。

本节介绍图像的几何变换,提供完整例程和运行结果:位置变换:平移,旋转,镜像;形状变换:缩放,扭变;投影变换:透视投影,平行投影;极坐标变换。

欢迎关注 『youcans 的 OpenCV 学习课』 系列,持续更新
youcans 的 OpenCV 学习课—1.安装与环境配置
youcans 的 OpenCV 学习课—2.图像读取与显示
youcans 的 OpenCV 学习课—3.图像的创建与修改
youcans 的 OpenCV 学习课—4.图像的叠加与混合
youcans 的 OpenCV 学习课—5.图像的几何变换
youcans 的 OpenCV 学习课—6.灰度变换与直方图处理
youcans 的 OpenCV 学习课—7.空间域图像滤波
youcans 的 OpenCV 学习课—8.频率域图像滤波(上)
youcans 的 OpenCV 学习课—9.频率域图像滤波(下)


1. 几何变换简介

几何变换是指对对图像的位置、大小、形状、投影进行变换,是将图像从原始平面投影到新的视平面。OpenCV 中的图像以多维数组描述,几何变换本质上是将一个多维数组通过映射关系求得另一个多维数组。

几何变换可以分为等距变换、相似变换、仿射变换和投影变换。在很多书籍中把等距变换、相似变换都称为仿射变换,常见的仿射变换包括平移、旋转、缩放、翻转、斜切等方法。

  • 等距变换:图像中的长度、面积不变,典型的等距变换是 平移、旋转
  • 相似变换:图像中的长度比、夹角、虚圆点不变,相似变换是在等距变换的基础上进行了缩放,典型的相似变换是 缩放
  • 仿射变换:图像中的平行关系、面积比、共线线段或平行线段的长度比、矢量的线性组合不变,仿射变换是旋转和非均匀缩放的复合,典型的仿射变换是 斜切
  • 投影变换:图像中的共点、共线、相交、相切、拐点的关系不变,,投影变换是在仿射变换基础上进行的非线性缩放,典型的投影变换是 透视

1.1 仿射变换

仿射变换(affine)的特点是原始图像中的平行关系和线段长度比例关系保持不变。

OpenCV 中的图像以多维数组描述,通过仿射变换变换为另一个多维数组(转换图像)。

仿射变换中的校正图像在二维空间中完成,在几何上定义为一个线性变换接一个平移变换。

仿射变换由以下公式描述:
[x~y~1]=MA[xy1],MA=[a11a12a13a21a22a23001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_A \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_A= \begin{bmatrix} a_{11} &a_{12} &a_{13}\\ a_{21} &a_{22} &a_{23}\\ 0 &0 &1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=MA​⎣⎡​xy1​⎦⎤​,MA​=⎣⎡​a11​a21​0​a12​a22​0​a13​a23​1​⎦⎤​

OpenCV 提供了 cv2.warpAffine 函数实现仿射变换的操作。

仿射变换矩阵 MA 中有 6 个未知参数,cv2.getAffineTransform 根据图像中不共线的 3 个点在变换前后的对应位置坐标,构造 6元一次方程组即可求出仿射变换矩阵 MA。cv2.warpAffine 再用变换矩阵 MA 计算得到变换后的图像。

基本例程:1.33 图像的仿射变换

    # 1.33 仿射变换: 平移、镜像、旋转 (cv2.warpAffine)img = cv2.imread("../images/imgB2.jpg")  # 读取彩色图像(BGR)rows, cols, ch = img.shapepts1 = np.float32([[50, 50], [200, 50], [50, 200]])  # 初始位置pts2 = np.float32([[50, 100], [200, 50], [100, 250]])  # 终止位置MA = cv2.getAffineTransform(pts1, pts2)  # 计算 2x3 变换矩阵 MAdst = cv2.warpAffine(img, MA, (cols, rows))  # 实现仿射变换plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")plt.subplot(122), plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)), plt.title("warpAffine")plt.show()

1.2 投影变换

投影变换(Projective mapping)也称透视变换(Perspective transformation),其特点是:原始图像中的平行关系、比例关系在转换后可以改变,但直线在转换后仍然保持直线。

投影变换将图片投影到一个新的视平面(Viewing plane),可以对三维空间中的物体旋转进行校正,主要用于图像拼接和校正透视投影导致的图像失真 。


投影变换由以下公式描述:
[x~y~z~]=M[xyz],M=[a11a12a13a21a22a23a31a32a33]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ \tilde{z} \end{bmatrix} = M \begin{bmatrix} x\\ y\\ z \end{bmatrix} ,\hspace{1em} M= \begin{bmatrix} a_{11} &a_{12} &a_{13}\\ a_{21} &a_{22} &a_{23}\\ a_{31} &a_{32} &a_{33} \end{bmatrix} ⎣⎡​x~y~​z~​⎦⎤​=M⎣⎡​xyz​⎦⎤​,M=⎣⎡​a11​a21​a31​​a12​a22​a32​​a13​a23​a33​​⎦⎤​

OpenCV 提供了 cv2.warpPerspective 函数实现投影变换的操作。cv2.getPerspectiveTransform 根据图像中不共线的 4 个点在变换前后的对应位置求得 (3x3) 变换矩阵,cv2.warpPerspective 使用该 (3x3) 变换矩阵即可求出变换后的图像。

1.3 极坐标变换

极坐标变换可以校正图像中的圆形物体和圆环中所包含的物体。

极坐标变换由以下公式描述:

KaTeX parse error: No such environment: align* at position 8: \begin{̲a̲l̲i̲g̲n̲*̲}̲ r &= \sqrt{(x-…

OpenCV 提供了 cv2.cartToPolar 函数和 cv2.ploarToCart 函数实现笛卡尔坐标与极坐标的相互转换。


2. 图像的平移

平移是物体位置在水平和垂直方向的移动。

像素点 (x,y) 沿 x 轴平移 dx、沿 y 轴平移 dy,可以由以下公式描述:
[x~y~1]=MAT[xy1],MAT=[10dx01dy001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AT} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AT} = \begin{bmatrix} 1 &0 &d_x\\ 0 &1 &d_y\\ 0 &0 &1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=MAT​⎣⎡​xy1​⎦⎤​,MAT​=⎣⎡​100​010​dx​dy​1​⎦⎤​

由偏移量 (Tx, Ty) 按上式构造平移变换矩阵 MAT,由函数 cv2.warpAffine 可以计算变换后的平移图像。

函数说明:

cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst

函数 cv2.warpAffine() 通过变换矩阵 M 对图像 src 进行仿射变换。

参数说明:

  • scr:变换操作的输入图像
  • M:仿射变换矩阵,2行3列
  • dsize: 输出图像的大小,二元元组 (width, height)
  • dst:变换操作的输出图像,可选项
  • flags:插值方法,整型(int),可选项
    • cv2.INTER_LINEAR:线性插值,默认选项
    • cv2.INTER_NEAREST:最近邻插值
    • cv2.INTER_AREA:区域插值
    • cv2.INTER_CUBIC:三次样条插值
    • cv2.INTER_LANCZOS4:Lanczos 插值
  • borderMode:边界像素方法,整型(int),可选项,默认值为 cv2.BORDER_REFLECT
  • borderValue:边界填充值,可选项,默认值为 0(黑色填充)
  • 返回值:dst,变换操作的输出图像,ndarray 多维数组

注意事项:

  1. 变换前后的图像 src、dst 都是 ndarray 二维数组。
  2. 变换矩阵 M 反映平移或旋转的关系,是 np.float32 类型 ndarray 二维数组(2行*3列)。
  3. 平移变换矩阵 M = [(1,0,dx), (0,1,dy)],Tx 表示向右(负值向左)移动像素点数,Ty 表示向下(负值向上)移动像素点数。
  4. 输出图像的大小 dsize 的格式为元组 (width,height)。

基本例程:1.34 图像的平移

    # 1.34 图像平移 (Translation transform)img = cv2.imread("../images/imgLena.tif")  # 读取彩色图像(BGR)rows, cols, ch = img.shapedx, dy = 100, 50  # dx=100 向右偏移量, dy=50 向下偏移量MAT = np.float32([[1, 0, dx], [0, 1, dy]])  # 构造平移变换矩阵   # dst = cv2.warpAffine(img, MAT, (cols, rows))  # 默认为黑色填充dst = cv2.warpAffine(img, MAT, (cols, rows), borderValue=(255,255,255))  # 设置白色填充plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")plt.subplot(122), plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)), plt.title("Translational")plt.show()


3. 图像的旋转

  • 图像以原点 (0, 0) 为中心、顺时针旋转角度 θ 进行旋转操作,可以由以下公式描述:

[x~y~1]=MAR[xy1],MAR=[cosθ−sinθ0sinθcosθ0001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AR} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} , M_{AR} = \begin{bmatrix} cos \theta &-sin \theta &0\\ sin \theta &cos \theta &0\\ 0 &0 &1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=MAR​⎣⎡​xy1​⎦⎤​,MAR​=⎣⎡​cosθsinθ0​−sinθcosθ0​001​⎦⎤​

按上式构造旋转变换矩阵 MAR,由函数 cv2.warpAffine 可以计算变换后的绕原点旋转图像。

  • 图像以任意点 (x0, y0) 为旋转中心、顺时针旋转角度 θ 的旋转操作,可以先将原点平移到旋转中心 (x0, y0) ,然后按照原点旋转,最后再平移回坐标原点,可以由以下公式描述:

[x~y~1]=[10x001y0001][cosθ−sinθ0sinθcosθ0001][10−x001−y0001][xy1]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix}= \begin{bmatrix} 1 &0 &x_0\\ 0 &1 &y_0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} cos \theta &-sin \theta &0\\ sin \theta &cos \theta &0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} 1 &0 &-x_0\\ 0 &1 &-y_0\\ 0 &0 &1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=⎣⎡​100​010​x0​y0​1​⎦⎤​⎣⎡​cosθsinθ0​−sinθcosθ0​001​⎦⎤​⎣⎡​100​010​−x0​−y0​1​⎦⎤​⎣⎡​xy1​⎦⎤​

  • 简便地,OpenCV 提供了 cv2.getRotationMatrix2D 函数, 根据旋转角度和位移计算旋转变换矩阵 MAR。

函数说明:

cv2.getRotationMatrix2D(center, angle, scale) → M

函数 getRotationMatrix2D 根据旋转参数计算旋转变换矩阵 MAR。

参数说明:

  • center:旋转中心坐标,二元元组 (x0, y0)
  • angle:旋转角度,单位为角度,逆时针为正数,顺时针为负数
  • scale: 缩放因子
  • 返回值:M, 旋转变换矩阵,2行3列

注意事项:

  1. 求出旋转变换矩阵 MAR,由函数 cv2.warpAffine 可以实现任意角度和任意中心的旋转效果。
  2. 以图像中心作为旋转中心时,可以用 img.shape 获得图像的宽度和高度值,除以 2 就是图像中心点坐标。
  3. 旋转角度为 90,180,270 度时,可以用 cv2.rotate(src, rotateCode) 函数实现,该方法实际上是通过矩阵转置实现的,因此速度很快。

基本例程:1.35 图像的旋转(以原点为中心旋转)

    # 1.35 图像旋转 (以原点 (0,0) 为中心旋转)img = cv2.imread("../images/imgLena.tif")  # 读取彩色图像(BGR)rows, cols, ch = img.shapetheta = np.pi / 8.0  # 顺时针旋转角度cosTheta = np.cos(theta)sinTheta = np.sin(theta)MAT = np.float32([[cosTheta, -sinTheta, 0], [sinTheta, cosTheta, 0]])  # 构造旋转变换矩阵# dst = cv2.warpAffine(img, MAT, (cols, rows))  # 默认为黑色填充dst = cv2.warpAffine(img, MAT, (cols, rows), borderValue=(255,255,255))  # 设置白色填充plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Origin")plt.subplot(122), plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB)), plt.title("Rotation")plt.show()

基本例程:1.36 图像的旋转(任意旋转中心)

    # 1.36 图像旋转 (以任意点 (x0,y0) 为中心旋转)img = cv2.imread("../images/imgGaia.tif")  # 读取彩色图像(BGR)height, width = img.shape[:2]  # 图片的高度和宽度theta1, theta2 = 30, 45  # 顺时针旋转角度,单位为角度x0, y0 = width//2, height//2  # 以图像中心作为旋转中心MAR1 = cv2.getRotationMatrix2D((x0,y0), theta1, 1.0)MAR2 = cv2.getRotationMatrix2D((x0,y0), theta2, 1.0)imgR1 = cv2.warpAffine(img, MAR1, (width, height))  # 旋转变换,默认为黑色填充imgR2 = cv2.warpAffine(img, MAR2, (width, height), borderValue=(255,255,255))  # 设置白色填充plt.figure(figsize=(10,6))plt.subplot(131), plt.axis('off'), plt.title(r"$Origin$")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))plt.subplot(132), plt.axis('off'), plt.title(r"$Rotation {}^o$".format(theta1))plt.imshow(cv2.cvtColor(imgR1, cv2.COLOR_BGR2RGB))plt.subplot(133), plt.axis('off'), plt.title(r"$Rotation {}^o$".format(theta2))plt.imshow(cv2.cvtColor(imgR2, cv2.COLOR_BGR2RGB))plt.show()

扩展例程:1.37 图像的直角旋转

当旋转角度为 90,180,270 度时,可以用图像旋转函数 cv2.rotate(src, rotateCode) 实现,该方法通过矩阵转置实现,速度很快。此外,numpy 中也提供了旋转矩阵的方法 np.rot90 可以按 90 度的整数倍进行旋转。

    # 1.37 图像的直角旋转 (90, 180, 270)# cv2.rotate(src, rotateCode)# rotateCode: cv2.ROTATE_90_CLOCKWISE, 顺时针旋转90度#             cv2.ROTATE_180, 顺时针旋转180度#             cv2.ROTATE_90_COUNTERCLOCKWISE, 顺时针旋转270度img = cv2.imread("../images/imgLena.tif")  # 读取彩色图像(BGR)imgR90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)imgR180 = cv2.rotate(img, cv2.ROTATE_180)imgR270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)# imgR90 = np.rot90(img, 1)  # numpy 矩阵旋转 90*1=90 度# imgR180 = np.rot90(img, 2)  # numpy 矩阵旋转 90*2=180 度# imgR270 = np.rot90(img, 3)  # numpy 矩阵旋转 90*3=270 度plt.figure(figsize=(9,7))plt.subplot(221), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title(r"$Origin$")plt.subplot(222), plt.imshow(cv2.cvtColor(imgR90, cv2.COLOR_BGR2RGB)), plt.title(r"$Rotation 90^{o}$")plt.subplot(223), plt.imshow(cv2.cvtColor(imgR180, cv2.COLOR_BGR2RGB)), plt.title(r"$Rotation 180^{o}$")plt.subplot(224), plt.imshow(cv2.cvtColor(imgR270, cv2.COLOR_BGR2RGB)), plt.title(r"$Rotation 270^{o}$")plt.show()


4. 图像的翻转(镜像)

翻转也称镜像,是指将图像沿轴线进行轴对称变换。水平镜像是将图像沿垂直中轴线进行左右翻转,垂直镜像是将图像沿水平中轴线进行上下翻转,水平垂直镜像是水平镜像和垂直镜像的叠加。

以水平镜像为例,图像宽度为 fw,像素点 (x,y) 以垂直中轴线为中心进行左右对换,可以由以下公式描述:
[x~y~1]=MAF[xy1],MAF=[−10fw010001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AF} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AF} = \begin{bmatrix} -1 &0 &f_w\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=MAF​⎣⎡​xy1​⎦⎤​,MAF​=⎣⎡​−100​010​fw​01​⎦⎤​

由上式构造镜像变换矩阵 MAF,由函数 cv2.warpAffine 可以计算变换后的镜像图像。

简便地,OpenCV 提供了 cv2.flip 函数,可以将图像沿水平方向、垂直方向、或水平/垂直方向同时进行翻转。

函数说明:

cv2.flip(src, flipCode[, dst]) -> dst

参数说明:

  • scr:变换操作的输入图像
  • flipCode:控制参数,整型(int),flipCode>0 水平翻转,flipCode=0 垂直翻转,flipCode<0 水平和垂直翻转
  • dst:变换操作的输出图像,可选项

基本例程:1.38 图像的翻转(镜像)

    # 1.38 图像的翻转 (镜像)img = cv2.imread("../images/Fractal03.png")  # 读取彩色图像(BGR)imgFlip1 = cv2.flip(img, 0)  # 垂直翻转imgFlip2 = cv2.flip(img, 1)  # 水平翻转imgFlip3 = cv2.flip(img, -1)  # 水平和垂直翻转plt.figure(figsize=(9, 6))plt.subplot(221), plt.axis('off'), plt.title("Original")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))  # 原始图像plt.subplot(222), plt.axis('off'), plt.title("Flipped Horizontally")plt.imshow(cv2.cvtColor(imgFlip2, cv2.COLOR_BGR2RGB))  # 水平翻转plt.subplot(223), plt.axis('off'), plt.title("Flipped Vertically")plt.imshow(cv2.cvtColor(imgFlip1, cv2.COLOR_BGR2RGB))  # 垂直翻转plt.subplot(224), plt.axis('off'), plt.title("Flipped Horizontally & Vertically")plt.imshow(cv2.cvtColor(imgFlip3, cv2.COLOR_BGR2RGB))  # 水平垂直翻转plt.show()


5. 图像的缩放

缩放只是调整图像的大小。

OpenCV 提供了 cv2.resize 函数,实现图像的缩放和大小变换 。

函数说明:

cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) → dst

参数说明:

  • scr:变换操作的输入图像
  • dsize: 输出图像的大小,二元元组 (width, height)
  • dst:变换操作的输出图像,可选项
  • fx, fy:x 轴、y 轴上的缩放比例,实型,可选项
  • interpolation:插值方法,整型,可选项
    • cv2.INTER_LINEAR:双线性插值(默认方法)
    • cv2.INTER_AREA:使用像素区域关系重采样,缩小图像时可以避免波纹出现
    • cv2.INTER_NEAREST:最近邻插值
    • cv2.INTER_CUBIC:4x4 像素邻域的双三次插值
    • cv2.INTER_LANCZOS4:8x8 像素邻域的Lanczos插值
  • 返回值:dst,变换操作的输出图像,ndarray 多维数组

注意事项:

  1. 图像缩放可以通过 dsize 直接设定输出图像的大小,也可以通过 dx, dy 设置图像缩放的比例(dsize 设为 None)。

  2. 也可以通过构造缩放变换矩阵 MAZ,由函数 cv2.warpAffine 计算变换后的缩放平移图像。缩放变换矩阵 MAZ 由以下公式描述:

[x~y~1]=MAZ[xy1],MAZ=[fx000fy0001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AZ} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AZ} = \begin{bmatrix} f_x &0 &0\\ 0 &f_y &0\\ 0 &0 &1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=MAZ​⎣⎡​xy1​⎦⎤​,MAZ​=⎣⎡​fx​00​0fy​0​001​⎦⎤​

由偏移量 (Tx, Ty) 按上式构造平移变换矩阵 MAT,由函数 cv2.warpAffine 可以计算变换后的平移图像。

基本例程:1.39 图像的缩放变换

    # 1.39 图像的缩放img = cv2.imread("../images/Fractal08.png")  # 读取彩色图像(BGR)height, width = img.shape[:2]  # 图片的高度和宽度imgZoom1 = cv2.resize(img, (int(0.75*width), int(height)))imgZoom2 = cv2.resize(img, None, fx=0.75, fy=1.0, interpolation=cv2.INTER_AREA)plt.figure(figsize=(8,6))plt.subplot(121), plt.axis('off'), plt.title("Zoom: 0.75*W,1.0*H")plt.imshow(cv2.cvtColor(imgZoom1, cv2.COLOR_BGR2RGB))plt.subplot(122), plt.axis('off'), plt.title("Zoom: fx=0.75,fy=1.0")plt.imshow(cv2.cvtColor(imgZoom2, cv2.COLOR_BGR2RGB))plt.show()

扩展例程:1.40 图像金字塔

图像金字塔是一种以多分辨率来解释图像的结构,常用于图像分割、图像压缩和机器视觉。

在需要处理同一图像的不同分辨率的子图时,需要创建一组具有不同分辨率的原始图像。把最大的图像放在底部,最小的放在顶部,看起来就像一座金字塔,称为图像金字塔。

图像金字塔是一系列来源于同一张原始图像、以金字塔形状排列的分辨率逐步降低的图像集合。
金字塔的底部是原始图像的高分辨率的表示,顶部是低分辨率的近似。

OpenCV 为向下采样和向上采样提供了两个函数:cv2.pyrDowncv2.pyrUp

函数说明:

cv2.pyrDown(src, dst=None, dstsize=None, borderType=None) → dst  # 向下采样
cv2.pyrUp(src, dst=None, dstsize=None, borderType=None) → dst  # 向上采样

函数 cv2.pyrDown 是从高分辨率的大尺寸图像逐次向下采样得到一系列图像,构建一个金字塔,称为高斯金字塔(Gaussian pyramid),实际上是一个重复高斯平滑并重新对图像采样的过程。拉普拉斯金字塔每次向下采样后将再次向上采样,并记录残差信息,可以对图像进行最大程度的还原。

# 1.40 图像金字塔def GussianPyramid(image): # 高斯金字塔level = 2  # 金字塔的层数imgCopy = image.copy()pyramidImages = []  # 创建图像 Listfor i in range(level):dst = cv2.pyrDown(imgCopy)  # 下采样pyramidImages.append(dst)  # 添加到图像 Listcv2.imshow("pyramid down "+str(i), dst)imgCopy = dst.copy()return pyramidImagesimg = cv2.imread("../images/imgLena.tif")  # 读取彩色图像(BGR)
cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE)
cv2.imshow("input image", img)
GussianPyramid(img)  # 高斯图像金字塔
# LapalianPyramid(img)  # 拉普拉斯图像金字塔
cv2.waitKey(0)


6. 图像的扭变(错切)

图像的错切变换也称斜切,是指平面景物在投影平面上的非垂直投影,使图像中的图形在水平方向或垂直方向产生扭变。

以水平扭变为例,像素点 (x,y) 在水平方向发生扭变变成斜边,而在垂直方向的边不变,可以由以下公式描述:
[x~y~1]=MAS[xy1],MAS=[1tanθ0010001]\begin{bmatrix} \tilde{x}\\ \tilde{y}\\ 1 \end{bmatrix} = M_{AS} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} ,\hspace{1em} M_{AS} = \begin{bmatrix} 1 &tan \theta &0\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} ⎣⎡​x~y~​1​⎦⎤​=MAS​⎣⎡​xy1​⎦⎤​,MAS​=⎣⎡​100​tanθ10​001​⎦⎤​

由扭变角度 θ上式构造错切变换矩阵 MAS,由函数 cv2.warpAffine 可以计算变换后的扭变图像。

基本例程:1.41 图像的错切

    # 1.41 图像的错切img = cv2.imread("../images/imgB2.jpg")  # 读取彩色图像(BGR)height, width = img.shape[:2]  # 图片的高度和宽度MAS = np.float32([[1, 0.2, 0], [0, 1, 0]])  # 构造错切变换矩阵imgShear = cv2.warpAffine(img, MAS, (width, height))plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("imgOrigin")plt.subplot(122), plt.imshow(cv2.cvtColor(imgShear, cv2.COLOR_BGR2RGB)), plt.title("imgShear")plt.show()


7. 图像的复合变换

图像的复合变换是指对给定的图像连续进行多次上述的平移、旋转、翻转、缩放、错切等基本变换,也称为级联变换。

对给定图像按一定顺序执行若干次基本变换,其变换矩阵仍然可以用 3x3 阶变换矩阵表示。进一步地,对图像依次执行基本变换 F1、F2、…Fn 的变换矩阵分别为 M1、M2、…Mn,可以证明,以图像中心点为中心进行比例、旋转进行变换,则复合变换的变换矩阵 M 等于各基本变换矩阵依次相乘所得到的组合矩阵:
M=M1×M2×⋯×MnM = M_1 \times M_2 \times \dots \times M_n M=M1​×M2​×⋯×Mn​

缩放:
MAZ=[fx000fy0001]M_{AZ} = \begin{bmatrix} fx &0 &0\\ 0 &f_y &0\\ 0 &0 &1 \end{bmatrix} MAZ​=⎣⎡​fx00​0fy​0​001​⎦⎤​

旋转:
MAR=[cosθ−sinθ0sinθcosθ0001]M_{AR} = \begin{bmatrix} cos \theta &-sin \theta &0\\ sin \theta &cos \theta &0\\ 0 &0 &1 \end{bmatrix} MAR​=⎣⎡​cosθsinθ0​−sinθcosθ0​001​⎦⎤​

平移:
MAT=[10dx01dy001]M_{AT} = \begin{bmatrix} 1 &0 &d_x\\ 0 &1 &d_y\\ 0 &0 &1 \end{bmatrix} MAT​=⎣⎡​100​010​dx​dy​1​⎦⎤​

扭变:
MAS=[1tanθ0010001]M_{AS} = \begin{bmatrix} 1 &tan \theta &0\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} MAS​=⎣⎡​100​tanθ10​001​⎦⎤​

镜像:
MAF=[−10fw010001]M_{AF} = \begin{bmatrix} -1 &0 &f_w\\ 0 &1 &0\\ 0 &0 &1 \end{bmatrix} MAF​=⎣⎡​−100​010​fw​01​⎦⎤​

基本例程:1.42 图像的复合变换

    # 1.42 图像的复合变换img = cv2.imread("../images/imgLena.tif")  # 读取彩色图像(BGR)height, width = img.shape[:2]  # 图片的高度和宽度# (1) 缩放fx, fy = 0.6, 0.6MAZ = np.float32([[fx, 0, 0], [0, fy, 0]])  # 构造缩放变换矩阵imgT1 = cv2.warpAffine(img, MAZ, (width, height))  # 仿射变换, 黑色填充# (2) 平移dx, dy = 50, 200  # dx=100 向右偏移量, dy=50 向下偏移量MAT = np.float32([[1, 0, dx], [0, 1, dy]])  # 构造平移变换矩阵imgT2 = cv2.warpAffine(imgT1, MAT, (width, height), borderValue=(0,255,255))  # 实现仿射变换# (3) 旋转theta = -30 * np.pi / 180  # 逆时针旋转 30°cosTheta = np.cos(theta)sinTheta = np.sin(theta)MAR = np.float32([[cosTheta, -sinTheta, 0], [sinTheta, cosTheta, 0]])  # 构造旋转变换矩阵imgT3 = cv2.warpAffine(imgT2, MAR, (width, height), borderValue=(255,255,0))  # 实现仿射变换# (4) 扭曲theta = -30 * np.pi / 180  # 逆时针扭变 30°MAS = np.float32([[1, np.tan(theta), 0], [0, 1, 0]])  # 构造扭变变换矩阵imgT4 = cv2.warpAffine(imgT3, MAS, (width, height), borderValue=(255,0,255))  # 实现仿射变换plt.figure(figsize=(9,6))plt.subplot(221), plt.axis('off'), plt.title("T1:Zoom")plt.imshow(cv2.cvtColor(imgT1, cv2.COLOR_BGR2RGB)),plt.subplot(222), plt.axis('off'), plt.title("T2:Translation")plt.imshow(cv2.cvtColor(imgT2, cv2.COLOR_BGR2RGB))plt.subplot(223), plt.axis('off'), plt.title("T3:Rotation")plt.imshow(cv2.cvtColor(imgT3, cv2.COLOR_BGR2RGB))plt.subplot(224), plt.axis('off'), plt.title("T4:Shear")plt.imshow(cv2.cvtColor(imgT4, cv2.COLOR_BGR2RGB))plt.show()


8. 投影变换

投影变换(Projective mapping)也称透视变换(Perspective transformation)是建立两平面场之间的对应关系, 将图片投影到一个新的视平面(Viewing plane)。

OpenCV 提供了 cv2.warpPerspective 函数实现投影变换的操作。

函数说明:

cv2.getPerspectiveTransform(src, dst[,solveMethod]) → MP
cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst

函数cv2.getPerspectiveTransform 根据图像中不共线的 4 个点在变换前后的对应位置求得 (3x3) 变换矩阵,cv2.warpPerspective 使用该 (3x3) 变换矩阵即可求出变换后的图像。标量进行加法运算。

参数说明:

  • src:变换前图像四边形顶点坐标
  • dst:变换后图像四边形顶点坐标
  • solveMethod:矩阵分解方法,传递给 cv2.solve 求解变换矩阵 MP
    • cv2.DECOMP_LU:选择最优轴的高斯消去法,默认方法
    • cv2.DECOMP_SVD:奇异值分解(SVD)方法
    • cv2.DECOMP_EIG:特征值分解方法,src 必须对称
    • cv2.DECOMP_QR:QR(正交三角)分解
    • cv2.DECOMP_CHOLESKY:Cholesky LLT 分解
  • MP:透视变换矩阵,3行3列
  • dsize: 输出图像的大小,二元元组 (width, height)
  • dst:变换操作的输出图像,可选项
  • flags:插值方法,整型(int),可选项
    • cv2.INTER_LINEAR:线性插值,默认选项
    • cv2.INTER_NEAREST:最近邻插值
    • cv2.INTER_AREA:区域插值
    • cv2.INTER_CUBIC:三次样条插值
    • cv2.INTER_LANCZOS4:Lanczos 插值
  • borderMode:边界像素方法,整型(int),可选项,默认值为 cv2.BORDER_REFLECT
  • borderValue:边界填充模式,可选项,默认值为 0(黑色填充)
  • 返回值:dst,透视变换操作的输出图像,ndarray 多维数组

基本例程:1.43 图像的投影变换

    # 1.43 投影变换 (Projective mapping)img = cv2.imread("../images/imgB2.jpg")  # 读取彩色图像(BGR)h, w = img.shape[:2]  # 图片的高度和宽度pointSrc = np.float32([[0,0], [w-1,0], [0,h-100], [w-1, h-100]])  # 原始图像中 4点坐标pointDst = np.float32([[180,50], [w-180,50], [0,h-100], [w-1, h-100]])  # 变换图像中 4点坐标MP = cv2.getPerspectiveTransform(pointSrc, pointDst)  # 计算投影变换矩阵 MimgP = cv2.warpPerspective(img, MP, (512, 512))  # 用变换矩阵 M 进行投影变换plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original")plt.subplot(122), plt.imshow(cv2.cvtColor(imgP, cv2.COLOR_BGR2RGB)), plt.title("Projective")plt.show()

基本例程:1.44 图像的投影变换

    # 1.44 图像的投影变换img = cv2.imread("../images/imgC2.jpg")  # 读取彩色图像(BGR)h, w = img.shape[:2]  # 图片的高度和宽度pointSrc = np.float32([[0,0], [w,0], [0,h], [w,h]])  # 原始图像中 4点坐标pointDst = np.float32([[int(w/3), int(h/3)], [int(w*2/3), int(h/3)], [0,h], [w,h]])  # 变换图像中 4点坐标MP = cv2.getPerspectiveTransform(pointSrc, pointDst)  # 计算投影变换矩阵 MimgP = cv2.warpPerspective(img, MP, (w,h), flags=cv2.INTER_AREA, borderMode=cv2.BORDER_WRAP)plt.figure(figsize=(9,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original"), plt.axis('off')plt.subplot(122), plt.imshow(cv2.cvtColor(imgP, cv2.COLOR_BGR2RGB)), plt.title("Projective"), plt.axis('off')plt.show()


9. 直角坐标与极坐标的转换

函数 cv2.cartToPolar 用于将直角坐标(笛卡尔坐标)转换为极坐标,函数 cv2.polarToCart 用于将极坐标转换为直角坐标(笛卡尔坐标)。

圆形图案边缘上的文字经过及坐标变换后可以垂直的排列在新图像的边缘,便于对文字的识别和检测。

函数说明:

cv2.cartToPolar(x, y[, magnitude[, angle[, angleInDegrees]]]) → magnitude, angle
cv2.polarToCart(magnitude, angle[, x[, y[, angleInDegrees]]]) → x, y

函数 cv2.cartToPolar 实现将原点移动到变换中心后的直角坐标向极坐标的转换,输入参数为直角坐标系的横坐标、纵坐标,输出为极坐标系的向量值、角度值。

函数 cv2.polarToCart 实现将原点移动到变换中心后的极坐标向直角坐标的转换,输入参数为极坐标系的向量值、角度值,输出为直角坐标系的横坐标、纵坐标。

参数说明:

  • x, y:直角坐标系的横坐标、纵坐标,ndarray 多维数组,浮点型
  • magnitude, angle:极坐标系的向量值、角度值,ndarray 多维数组
  • angleInDegrees:弧度制/角度值选项,默认值 0 选择弧度制,1 选择角度制([0,360] )
  • 返回值 magnitude, angle:极坐标系的向量值、角度值,ndarray 多维数组,与输入的 x, y 具有相同的尺寸和数据类型
  • 返回值 x, y:直角坐标系的横坐标、纵坐标,ndarray 多维数组,与输入的 magnitude, angle 具有相同的尺寸和数据类型

注意事项:

  1. 极坐标与直角坐标的变换在数学上是可逆的,但实际变换时存在误差,角度计算精度约为 0.3度,坐标计算精度约为 1e-6。
  2. 直角坐标系以变换中心为圆心的同一个圆上的点,在极坐标系中显示为一条直线。因此,用极坐标变换可以实现圆形物体的图像修正。
  3. cv2.cartToPolar 中的可选项 magnitude, angle 可以用于指定变换中心的坐标,cv2.polarToCart 中的可选项 x, y 可以用于指定变换中心的坐标。

基本例程:1.45 直角坐标转换为极坐标

    # 1.45 直角坐标转换为极坐标x = np.float32([0,1,2, 0,1,2, 0,1,2]) -1y = np.float32([0,0,0, 1,1,1, 2,2,2]) -1n = np.arange(9)r, theta = cv2.cartToPolar(x, y, angleInDegrees=True)xr,yr = cv2.polarToCart(r, theta, angleInDegrees=1)print(xr,yr)plt.figure(figsize=(9,5))plt.subplot(121), plt.title("Cartesian coordinate"), plt.plot(x, y, 'o')for i, txt in enumerate(n):plt.annotate(txt, (x[i], y[i]))plt.subplot(122), plt.title("Polar coordinate"), plt.plot(r, theta, 'o')for i, txt in enumerate(n):plt.annotate(txt, (r[i], theta[i]))plt.show()

扩展例程:1.46 极坐标系中的圆形图像修正

    # 1.46 极坐标系中的圆形图像修正img = cv2.imread("../images/imgC3.jpg")  # 读取彩色图像(BGR)h, w = img.shape[:2]  # 图片的高度和宽度cx, cy = int(w/2), int(h/2)  # 以图像中心点作为变换中心maxR = max(cx, cy)  # 最大变换半径imgPolar = cv2.linearPolar(img, (cx,cy), maxR, cv2.INTER_LINEAR)imgPR = cv2.rotate(imgPolar, cv2.ROTATE_90_COUNTERCLOCKWISE)plt.figure(figsize=(10,6))plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("Original"), plt.axis('off')plt.subplot(122), plt.imshow(cv2.cvtColor(imgPR, cv2.COLOR_BGR2RGB)), plt.title("PolarTrans"), plt.axis('off')plt.show()

通过极坐标和直角坐标的对应关系,将圆环图像转换为矩形图像,可以对圆形图像进行修正。

【本节完】


版权声明:

youcans 的 OpenCV 学习课 @ youcans 原创作品
转载必须标注原文链接:https://blog.csdn.net/youcans/article/details/121288020
Copyright 2021 youcans, XUPT
Crated:2021-11-15

欢迎关注 『youcans 的 OpenCV 学习课』 系列,持续更新
youcans 的 OpenCV 学习课—1.安装与环境配置
youcans 的 OpenCV 学习课—2.图像读取与显示
youcans 的 OpenCV 学习课—3.图像的创建与修改
youcans 的 OpenCV 学习课—4.图像的叠加与混合
youcans 的 OpenCV 学习课—5.图像的几何变换
youcans 的 OpenCV 学习课—6.灰度变换与直方图处理
youcans 的 OpenCV 学习课—7.空间域图像滤波
youcans 的 OpenCV 学习课—8.频率域图像滤波(上)
youcans 的 OpenCV 学习课—9.频率域图像滤波(下)

youcans 的 OpenCV 学习课—5.图像的几何变换相关推荐

  1. youcans 的 OpenCV 学习课—4.图像的叠加与混合

    youcans 的 OpenCV 学习课-4.图像的叠加与混合 本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战. 本节介绍图像的加法.叠加与混合,提供完整例程和运行结果:加法 ...

  2. youcans 的 OpenCV 学习课—3.图像的创建与修改

    youcans 的 OpenCV 学习课-3.图像的创建与修改 本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战. OpenCV 中图像的数据结构是 ndarray 多维数组, ...

  3. youcans 的 OpenCV 学习课—2.图像读取与显示

    youcans 的 OpenCV 学习课-2.图像读取与显示 本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战. 本节介绍图像的读取.保存和显示.除基本方法和例程外,还给出了从 ...

  4. youcans 的 OpenCV 学习课—8.频率域图像滤波(上)

    欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV 学习课』 系列,持续更新中 youcans 的 OpenCV 学习课-1.安装与环境配置 yo ...

  5. youcans 的 OpenCV 学习课—10. 图像复原与重建

    youcans 的 OpenCV 学习课-10. 图像复原与重建 本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战. 图像复原是对图像退化过程建模,并以图像退化的先验知识来恢复 ...

  6. youcans 的 OpenCV 学习课—6.灰度变换与直方图处理

    youcans 的 OpenCV 学习课-6.灰度变换与直方图处理 本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战. 空间域的图像处理方法直接对图像的像素点进行处理,空间域图 ...

  7. youcans 的 OpenCV 学习课—1.安装与环境配置

    youcans 的 OpenCV 学习课-1.安装与环境配置 作者: youcans@xupt 本系列面向 Python 小白,从零开始实战解说 OpenCV 项目实战. 什么叫从零开始?从软件安装. ...

  8. 【youcans 的 OpenCV 学习课】7. 空间域图像滤波

    专栏地址:『youcans 的图像处理学习课』 文章目录:『youcans 的图像处理学习课 - 总目录』 [youcans 的 OpenCV 学习课]7. 空间域图像滤波 图像滤波是在尽可能保留图像 ...

  9. 【youcans 的图像处理学习课】22. Haar 级联分类器

    专栏地址:『youcans 的图像处理学习课』 文章目录:『youcans 的图像处理学习课 - 总目录』 [youcans 的图像处理学习课]22. Haar 级联分类器 3. Haar 特征及其加 ...

最新文章

  1. Activiti最全入门教程
  2. anjularjs 路由
  3. Advice for Students--开始学术研究
  4. 使用Log4jdbc记录JDBC操作
  5. [Tomcat报错]SEVERE: Error listenerStart
  6. svn .a文件上传不了
  7. python 命名管道_Linux 下 Python 读取命名管道的疑惑
  8. 深入理解JavaScript系列(21):S.O.L.I.D五大原则之接口隔离原则ISP
  9. linux搭建phantomjs+webdriver+testng+ant自动化工程
  10. 使用iWebOffice实现电子签章
  11. matlab simulink 单气室油气弹簧阻尼特性分析
  12. opengles加载obj格式3D模型含光照和纹理
  13. python可视化3d柱状图_「Python实现数据可视化」创建3D柱状图
  14. 2018春季校园招聘笔经面经合集:Java开发岗
  15. 让每个3D建模师都心动的:超详细人体结构构图分析
  16. 使用计算机VLOOKUP函数需注意什么,vlookup函数怎么用-vlookup函数使用方法介绍 - Iefans...
  17. Linux pwn入门教程——格式化字符串漏洞
  18. 谷歌优化的正确方法!
  19. css及css3学习
  20. 苹果无线显示与电视连接电脑连接电脑连接服务器,投屏黑科技!手把手教您,如何将笔记本电脑的画面无线投屏到电视或投影机上显示...

热门文章

  1. of方法:给集合一次性添加多个元素
  2. python 折线图中文乱码_彻底解决 Python画图中文乱码问题--Pyplotz组件
  3. 数字时钟html5 js,html5 canvas js(数字时钟)实例代码
  4. 三诺+n20g+微型计算机,原来是他?揭秘三诺永恒系列开山鼻祖
  5. linux 备份mysql并上传_Linux 网站目录和MySQL备份并上传FTP
  6. 约瑟夫环c语言程序完整版,C语言:约瑟夫环问题(源代码)
  7. linux查看etl进程,常见ETL工具
  8. MySQL——JSON_REPLACE()函数修改JSON属性值
  9. Java8————Lambda表达式(一)
  10. python排名上升_TIOBE:2019年7月全球编程语言排行 Python热度继续上升