Python+OpenCV实战之实现文档扫描

1. 介绍

实现文档扫描是图像处理和计算机视觉中常见的问题之一。本文将介绍使用Python和OpenCV图像处理库来实现文档扫描的方法。

2. 实现文档扫描的步骤

2.1 图像预处理

处理文档扫描前,需要先进行一系列的图像预处理。这些步骤包括:

图像灰度化:将图像转换为灰度图像,使得后续的处理更加简单。

高斯滤波:降噪,保留图像的主要特征。

边缘检测:检测图像中所有的边缘,包括文字和背景的边缘。

形态学处理:对边缘进行膨胀和腐蚀操作,使得边缘更加连续。

下面的代码展示了如何实现这些步骤:

import cv2

# 读取图片

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

# 图像灰度化

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 高斯滤波

blur = cv2.GaussianBlur(gray, (5, 5), 0)

# 边缘检测

edge = cv2.Canny(blur, 75, 200)

# 形态学处理

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

dilate = cv2.dilate(edge, kernel, iterations=1)

erode = cv2.erode(dilate, kernel, iterations=1)

2.2 寻找轮廓

上一步处理完后,需要找到图像中的所有轮廓。在找轮廓前,需要首先对图像进行腐蚀操作,使得图像中的所有小孔和不规则轮廓被填平,然后再寻找轮廓。

下面的代码展示了如何实现这些步骤:

# 找到所有轮廓

contours, _ = cv2.findContours(erode, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 寻找最大的轮廓

maxContour = max(contours, key=cv2.contourArea)

# 根据轮廓计算最小矩形

rect = cv2.minAreaRect(maxContour)

box = cv2.boxPoints(rect)

box = np.int0(box)

2.3 透视变换

根据在上一步得到的最小矩形的四个顶点的坐标,可以使用透视变换将图像变换为一个矩形。

下面的代码展示了如何实现这些步骤:

# 寻找四个顶点

tl, tr, br, bl = box

# 计算新图片的宽度和高度

widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))

widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))

maxWidth = max(int(widthA), int(widthB))

heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))

heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))

maxHeight = max(int(heightA), int(heightB))

# 变换后的四个点坐标

dst = np.array([

[0, 0],

[maxWidth - 1, 0],

[maxWidth - 1, maxHeight - 1],

[0, maxHeight - 1]], dtype="float32")

# 计算透视变换矩阵

M = cv2.getPerspectiveTransform(box, dst)

# 使用透视变换矩阵进行变换

warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))

3. 结果展示

下面是将以上步骤综合起来,实现文档扫描的最终代码:

import cv2

import numpy as np

# 读取图片

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

# 图像灰度化

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 高斯滤波

blur = cv2.GaussianBlur(gray, (5, 5), 0)

# 边缘检测

edge = cv2.Canny(blur, 75, 200)

# 形态学处理

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

dilate = cv2.dilate(edge, kernel, iterations=1)

erode = cv2.erode(dilate, kernel, iterations=1)

# 找到所有轮廓

contours, _ = cv2.findContours(erode, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 寻找最大的轮廓

maxContour = max(contours, key=cv2.contourArea)

# 根据轮廓计算最小矩形

rect = cv2.minAreaRect(maxContour)

box = cv2.boxPoints(rect)

box = np.int0(box)

# 寻找四个顶点

tl, tr, br, bl = box

# 计算新图片的宽度和高度

widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))

widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))

maxWidth = max(int(widthA), int(widthB))

heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))

heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))

maxHeight = max(int(heightA), int(heightB))

# 变换后的四个点坐标

dst = np.array([

[0, 0],

[maxWidth - 1, 0],

[maxWidth - 1, maxHeight - 1],

[0, maxHeight - 1]], dtype="float32")

# 计算透视变换矩阵

M = cv2.getPerspectiveTransform(box, dst)

# 使用透视变换矩阵进行变换

warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))

# 显示变换后的图片

cv2.imshow('output', warped)

cv2.waitKey(0)

下面是一张原始图片和处理后的结果对比图:

4. 总结

本文介绍了使用Python和OpenCV实现文档扫描的方法,通过对图像的预处理,寻找轮廓和透视变换等步骤,将图像中的文档扫描转换为一个矩形,方便后续的处理和识别。

后端开发标签