Python+OpenCV教程7:图像几何变换


主站:http://ex2tron.wang
原文:Python+OpenCV教程7:图像几何变换


学习如何旋转、平移和缩放图片,了解仿射/透视变换。图片等可到源码处下载。


目标

  • 实现旋转、平移和缩放图片
  • 了解仿射变换和透视变换
  • OpenCV函数:cv2.resize(), cv2.warpAffine(), cv2.warpPerspective()

教程

缩放图片

缩放就是调整图片的大小,使用cv2.resize()函数实现缩放。可以按照比例缩放,也可以按照指定的大小缩放:

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('drawing.jpg')

# 按照指定的宽度、高度缩放图片
res = cv2.resize(img, (132, 150))
# 按照比例缩放,如x,y轴均放大一倍
res2 = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)

cv2.imshow('shrink', res), cv2.imshow('zoom', res2)
cv2.waitKey(0)

我们也可以指定缩放方法interpolation,更专业点叫插值方法,默认是INTER_LINEAR,全部可以参考:InterpolationFlags

平移图片

这里涉及到仿射变换的概念,大家不用知道它的意思,只需要了解下面三点:

  • 仿射变换后,原图中平行的线依然平行
  • cv2.warpAffine()实现仿射变换
  • 仿射变换需要定义一个2*3维的变换矩阵

要平移图片,我们需要定义下面这样一个矩阵,tx,ty是向x和y方向平移的距离:

# 平移图片
rows, cols = img.shape[:2]

# 定义平移矩阵,需要是numpy的float32类型
# x轴平移100,y轴平移50
M = np.float32([[1, 0, 100], [0, 1, 50]])
# 用仿射变换实现平移
dst = cv2.warpAffine(img, M, (cols, rows))

cv2.imshow('shift', dst)
cv2.waitKey(0)

再次强调一下:图片的高度(y方向)是rows,宽度(x方向)是cols,请勿混淆。

Python+OpenCV教程7:图像几何变换_第1张图片
平移图片

旋转图片

旋转同平移一样,也需要定义一个变换矩阵。OpenCV直接提供了cv2.getRotationMatrix2D()函数用来生成这个矩阵,对这个矩阵的形式感兴趣的童鞋可以去引用查看:

# 45°旋转图片并缩小一半
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 0.5)
dst = cv2.warpAffine(img, M, (cols, rows))

cv2.imshow('rotation', dst)
cv2.waitKey(0)

cv2.getRotationMatrix2D()函数有三个参数:

  • 参数1:图片的旋转中心
  • 参数2:旋转角度
  • 参数3:缩放比例,该例中0.5表示我们缩小一半
Python+OpenCV教程7:图像几何变换_第2张图片
旋转45°并缩放

翻转图片

如果我们镜像翻转图片,可以用cv2.flip()函数:

dst = cv2.flip(img, 1)

其中参数2 = 0:垂直翻转(沿x轴),参数2 > 0: 水平翻转(沿y轴),参数2 < 0: 水平垂直翻转。

仿射变换

除了平移和旋转,如何实现任意的图像变换呢?同样的道理,我们需要一个变换矩阵。

要生成这个变换矩阵,需要定义变换前后的三个点,比如说:

# 变换前的三个点
pts1 = np.float32([[50, 65], [150, 65], [210, 210]])
# 变换后的三个点
pts2 = np.float32([[50, 100], [150, 65], [100, 250]])

# 生成变换矩阵
M = cv2.getAffineTransform(pts1, pts2)
dst = cv2.warpAffine(img, M, (cols, rows))

plt.subplot(121), plt.imshow(img), plt.title('input')
plt.subplot(122), plt.imshow(dst), plt.title('output')
plt.show()

变换前后的三个点我已经标记出来了。用cv2.getAffineTransform()生成变换矩阵,接下来再用cv2.warpAffine()实现变换。大家可以修改下变换后的三个点坐标看看效果:

Python+OpenCV教程7:图像几何变换_第3张图片
仿射变换前后对比图

透视变换

透视变换绝对是一项很酷的功能。我们经常会用手机去拍身份证和文件,无论你怎么拍,貌似都拍不正或者有边框。如果你使用过手机上面一些扫描类软件,比如"扫描全能王","Office Lens",它们能很好地矫正图片。这些软件就是应用透视变换实现的,跟仿射变换一样,我们不用知道它的具体原理。

透视变换后,原图中的直线依旧是直线。如下图,我们实现这个功能:

Python+OpenCV教程7:图像几何变换_第4张图片
矫正一鸣的卡片
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('card.jpg')
rows, cols = img.shape[:2]

# 原图中卡片的四个角点
pts1 = np.float32([[148, 80], [437, 114], [94, 247], [423, 288]])
# 变换后分别在左上、右上、左下、右下四个点
pts2 = np.float32([[0, 0], [320, 0], [0, 178], [320, 178]])

# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)
# 进行透视变换
dst = cv2.warpPerspective(img, M, (320, 178))

plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('input')
plt.subplot(122), plt.imshow(dst[:, :, ::-1]), plt.title('output')
plt.show()

透视变换需要前后四个点来生成3*3的变换矩阵,用cv2.getPerspectiveTransform()实现。然后再用cv2.warpPerspective()进行变换。代码中有个img[:, :, ::-1]还记得吗?忘记的话,请看练习。

是不是很简单?当然,我们后面学习了特征提取之后,就可以自动识别角点了。

小结

  • cv2.resize()缩放图片,可以按指定大小缩放,亦可以按比例缩放
  • 平移和旋转是靠cv2.warpAffine()仿射变换实现的,也可以自己定义变换前后的点,实现任意变换
  • 透视变换常用于矫正图片,是一个很酷的功能

练习

  1. 透视变换代码中有个img[:, :, ::-1],还记得吗?请复习:Matplotlib显示图像

引用

  • 本节源码
  • Geometric Transformations of Images

你可能感兴趣的:(Python+OpenCV教程7:图像几何变换)