说明:本文是《Python数据分析与数据化运营》中的“3.12.3 图像的基本预处理”。
-----------------------------下面是正文内容--------------------------
本示例中,将使用OpenCV来做图像基本预处理操作,基本处理内容包括图像缩放、平移、旋转、透视变换、图像色彩模式转换、边缘检测、二值化操作、平滑处理、形态学处理。
数据源文件sudoku.png、j.png位于“附件-chapter3”中,默认工作目录为“附件-chapter3”(如果不是,请cd切换到该目录下,否则会报类似“IOError: File sudoku.png does not exist”)。完整代码如下:
import cv2 # 导入图像处理库
import numpy as np # 导入numpy库
from matplotlib import pyplot as plt # 导入展示库
# 展示图像模块
def img_show(img_name, img):
cv2.imshow(img_name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 原始图像
img_file = 'sudoku.png' # 定义原始数据文件
img = cv2.imread(img_file) # 以彩色模式读取图像文件
rows, cols, ch = img.shape # 获取图像形状
img_show('raw img', img) # 展示彩色图像
# 图像缩放
img_scale = cv2.resize(img, None, fx=0.6, fy=0.6, interpolation=cv2.INTER_CUBIC) # 图像缩放
img_show('scale img', img_scale) # 展示缩放后的图像
# 图像平移
M = np.float32([[1, 0, 100], [0, 1, 50]]) # 定义平移中心
img_transform = cv2.warpAffine(img, M, (cols, rows)) # 平移图像
img_show('transform img', img_transform) # 展示平移后的图像
# 图像旋转
M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 45, 0.6) # 定义旋转中心
img_rotation = cv2.warpAffine(img, M, (cols, rows)) # 第一个参数为旋转中心,第二个为旋转角度,第三个为旋转后的缩放因子
img_show('rotation img', img_rotation) # 展示旋转后的图像
# 透视变换
pts1 = np.float32([[76, 89], [490, 74], [37, 515], [520, 522]]) # 定义变换前的四个校准点
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]]) # 定义变换后的四个角点
M = cv2.getPerspectiveTransform(pts1, pts2) # 定义变换中心点
img_perspective = cv2.warpPerspective(img, M, (300, 300)) # 透视变换
img_show('perspective img', img_perspective) # 展示透视变换后的图像
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 图像转灰度
img_show('gray img', img_gray) # 展示灰度图像
# 边缘检测
img_edges = cv2.Canny(img, 100, 200) # 检测图像边缘
img_show('edges img', img_edges) # 展示图像边缘
# 图像二值化
ret, th1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) # 简单阀值
th2 = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2) # 自适应均值阀值
th3 = cv2.adaptiveThreshold(img_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 自适应高斯阀值
titles = ['Gray Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding'] # 定义图像标题
images = [img_gray, th1, th2, th3] # 定义图像集
for i in xrange(4):
plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray') # 以灰度模式展示每个子网格的图像
plt.title(titles[i]) # 设置每个自网格标题
plt.xticks([]), plt.yticks([]) # 设置x轴和y轴标题
plt.show() # 展示图像
# 图像平滑
kernel = np.ones((5, 5), np.float32) / 25 # 设置平滑内核大小
img_smoth_filter2D = cv2.filter2D(img, -1, kernel) # 2D卷积法
img_smoth_blur = cv2.blur(img, (5, 5)) # 平均法
img_smoth_gaussianblur = cv2.GaussianBlur(img, (5, 5), 0) # 高斯模糊
img_smoth_medianblur = cv2.medianBlur(img, 5) # 中值法
titles = ['filter2D', 'blur', 'GaussianBlur', 'medianBlur'] # 定义标题集
images = [img_smoth_filter2D, img_smoth_blur, img_smoth_gaussianblur, img_smoth_medianblur] # 定义图像集
for i in xrange(4):
plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray') # 以灰度模式展示每个子网格的图像
plt.title(titles[i]) # 设置每个自网格标题
plt.xticks([]), plt.yticks([]) # 设置x轴和y轴标题
plt.show() # 展示全部图像
# 形态学处理
img2 = cv2.imread('j.png', 0) # 以灰度模式读取图像
kernel = np.ones((5, 5), np.uint8) # 设置形态学处理内核大小
erosion = cv2.erode(img2, kernel, iterations=1) # 腐蚀
dilation = cv2.dilate(img2, kernel, iterations=1) # 膨胀
plt.subplot(1, 3, 1), plt.imshow(img2, 'gray') # 设置自网格1图像
plt.subplot(1, 3, 2), plt.imshow(erosion, 'gray') # 设置自网格2图像
plt.subplot(1, 3, 3), plt.imshow(dilation, 'gray') # 设置自网格3图像
plt.show() # 展示全部图像
上述代码以空行分为11个部分,涵盖了日常图像处理的常用操作。
第一部分为导入库,本代码中除了OpenCV库外,还有Numpy用于定义图像处理的内核、Matplotlib用于展示多图图像。
第二部分定义了一个函数,用来做单图像展示。下面的每个功能模块,当只有一个图像做展示了会直接调用该模块,而无需重复写展示功能代码。cv2.show()方法必须与cv2.waitKey()、cv2.destroyAllWindows()一起使用才能保证图像正常展示以及关闭功能。
第三部分读取原始图像并展示。通过cv2的imread方法以彩色模式读取图像,然后获得彩色图像的长、高和通道形状,最终调用img_show做图像展示,结果如图3-10中的①图像
第四部分图像缩放处理。直接使用cv2.resize方法设置缩放比例、方法等并展示输出为原图像60%的新图像,结果如图3-10中的②图像。
第五部分图像平移处理。先定义图像平移中心,然后使用cv2.warpAffine方法根据平移中心移动图像,移动后的图像,结果如图3-10中的③图像。
第六部分图像旋转处理。与图像平移类似,先定义旋转中心,然后使用cv2.warpAffine进行旋转,同时设置旋转角度45度、缩放因子为0.6,结果如图3-10中的④图像。
第七部分透视变换处理。先定义变换前的四个校准点,然后定义变换后的四个角点,可用来控制图像大小,接着定义变换中心点并应用cv2.warpPerspective进行透视变换,,结果如图3-10中的⑤图像。
第八部分转换为灰度图像。使用cv2.cvtColor将BRG模式转为GRAY模式,结果如图3-10中的⑥图像。
![d9ae355dc071040a2ee2dba046a5b00e.png](https://i-blog.csdnimg.cn/blog_migrate/65a20e7632aeec9f5fca13ff79f3324d.jpeg)
图3-10 原始图像和部分处理后的图像
第九部分边缘检测处理。使用cv2.Canny检测图像边缘,结果如图3-11.
![dd80475e2d302858258f73b90ca5a92c.png](https://i-blog.csdnimg.cn/blog_migrate/2a0db7bb3942105925dceae99c1754dd.jpeg)
图3-11边缘检测后的图像
第十部分图像二值化处理。这里分别应用了简单阀值、自适应均值阀值、自适应高斯阀值三种方法做二值化处理,并使用Matplotlib做多网格图像,同时展示原始图像和三种阀值下二值化图像处理结果,如图3-12.
![6dc496fb596751031bc2930d364eb69f.png](https://i-blog.csdnimg.cn/blog_migrate/f9a4200eb0ef958627e3ce6e0bc470da.jpeg)
图3-12原图和多种阀值控制下的二值化结果
第十一部分图像平滑处理。先设置平滑内核大小,然后分别使用cv2.filter2D(3D卷积)、cv2.blur(平均法)、cv2.GaussianBlur(高斯模糊)、cv2.medianBlur(中值法)进行平滑结果对比,如图3-13:
![21473b262b90c37599f3fdcd16b8ca14.png](https://i-blog.csdnimg.cn/blog_migrate/44f5ae52df67bcf0a5e344366c2e6bf4.jpeg)
图3-13多种平滑效果对比
第十二部分形态学处理。这里重新以灰度模式读取一个图像,定义处理内核之后,通过cv2.erode和cv2.dilate分别实现腐蚀和膨胀操作。原图和腐蚀、膨胀处理后的图像对比如下:
![5ba295d0b2cdd05dc10e470041df0312.png](https://i-blog.csdnimg.cn/blog_migrate/88c379be477607be1b4e8e660ae33d53.jpeg)
图3-14原图和腐蚀、膨胀处理效果
上述过程中,主要需要考虑的关键点是:如何根据不同的图像处理需求,实现图像的基本预处理任务,尤其是对于每种方法下参数的具体设置,需要根据实际情况加以选择。另外,在程序自动化过程中,是不可能依靠人工参与每次边界调整、阀值优化等具体过程,这往往通过一定专用的参数优化模型来实现。例如,对于透视图像的处理,首先要做的识别出透视图像的矫正参照点,而该过程就是一个融合了业务场景、图像处理技术、数学知识和计算方法等多学科知识的建模过程。
代码实操小结:本小节示例中,主要用了几个知识点:
- 通过cv2.imread对图像文件的数据读取,并分别以彩色和灰度模式读取图像
- 通过cv2.imshow、cv2.waitKey()、cv2.destroyAllWindows()实现图像展示
- 通过Matplotlib库实现多子自网格图的展示
- 通过cv2.resize实现图像缩放
- 通过cv2.warpAffine实现图像平移
- 通过cv2.warpAffine和cv2.getRotationMatrix2D实现图像旋转
- 通过cv2. warpPerspective和cv2.getPerspectiveTransform实现图像透视变换
- 通过cv2.cvtColor实现图像颜色模式转换
- 通过cv2.Canny实现图像边缘检测
- 通过cv2.threshold实现图像二值化处理,并通过简单阀值、自适应均值阀值、自适应高斯阀值等方法寻找最佳阀值
- 通过cv2.filter2D、cv2.blur、cv2.GaussianBlur、cv2.medianBlur等方法实现图像平滑处理
- 通过for循环做数据循环输出
- 通过cv2.erode、cv2.dilate等方法实现图像腐蚀、膨胀等形态学处理