加载必要的包和读取图像路径。
# 利用透视变换对纸张进行矫形
import cv2
import numpy as np
import math
im = cv2.imread('../img_data/paper.jpg')
cv2.imshow('im', im)
显示原始图像:
# 灰度化
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
cv2.imshow('im_gray', im_gray)
灰度化图像并显示:
canny边沿提取图像的轮廓
im_canny = cv2.Canny(im_gray,
70, 300, 3)
cv2.imshow('im_canny', im_canny)
canny轮廓如下所示:
取出canny边沿提取的边沿点的数据,并将不同的轮廓按照面积排序,找出四边形的轮廓,并储存起来。
# 在canny边沿提取的结果之上进行轮廓的检测
cnts, hie = cv2.findContours(
im_canny,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_NONE
)
# 对轮廓按照面积排序(倒)
docCnt = None
if len(cnts) > 0:
cnts = sorted(cnts,
key=cv2.contourArea, # 根据该函数计算的结果排序
reverse=True
)
# 对排序后的轮廓执行多边形拟合
for c in cnts:
peri = cv2.arcLength(c, True) # 计算周长
# 多边形拟合
approx = cv2.approxPolyDP(c, 0.02 * peri, True)
if len(approx) == 4: # 四边形
docCnt = approx
break
print(docCnt) # 打印纸张的轮廓
在原图上标记纸张轮廓的四个顶点,并显示出来
points = []
for peaks in docCnt:
peak = peaks[0]
# 在角点绘制小圆圈
cv2.circle(im, tuple(peak), 10, (0, 0, 255), 2)
points.append(peak)
cv2.imshow('im_point', im)
纸张的四个角点标记图如下所示:
计算纸张原本的高度和宽度,并将斜着的图片透视变换到竖直方向的矩阵。
# 计算纸张的高度 宽度
dw = points[1][0] - points[0][0]
dh = points[1][1] - points[0][1]
h = int(math.sqrt(dw ** 2 + dh ** 2))
dw = points[2][0] - points[1][0]
dh = points[2][1] - points[1][1]
w = int(math.sqrt(dw ** 2 + dh ** 2))
src = np.float32(
[[points[0], points[1], points[2], points[3]]] # 原顶点
)
dst = np.float32([[0, 0], [0, h], [w, h], [w, 0]])
# 生成透视变换矩阵
m = cv2.getPerspectiveTransform(src, dst)
result = cv2.warpPerspective(im_gray, m, (w, h)) # 透视变换
cv2.imshow('result', result)
cv2.waitKey()
cv2.destroyAllWindows()