话不多说直接上代码:
import cv2
import numpy as np
def xian(img): # 显示图象
cv2.imshow('dabo', img)
cv2.waitKey(0)
img = cv2.imread('D:\\picture\\dabo\\ppt.jpg') # 读图,因为图片太大要缩小
img = cv2.resize(img, None, fx=0.5, fy=0.5)
xian(img)
h, w, c = img.shape
gray1 = cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) # 先转灰,再二值化,最后找轮廓并画出
thresh1 = cv2.threshold(gray1, 175, 255, cv2.THRESH_BINARY)[1]
xian(thresh1)
contours1 = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
res_new = img.copy()
res = cv2.drawContours(res_new, contours1, -1, (0, 0, 255), 2)
xian(res)
max = contours1[0] # 找出面积最大的轮廓(ppt的轮廓)
for i in contours1:
if cv2.contourArea(i) > cv2.contourArea(max):
max = i
print(cv2.contourArea(max)) # 检查是不是大的
tu1 = np.zeros((h, w, c), np.uint8) # 用一张空图画出最大面积的轮廓(ppt的轮廓),方便以后找角点
res_goal = cv2.drawContours(tu1.copy(), max, -1, (0, 0, 255), 2)
xian(res_goal)
epsilon = 0.1 * cv2.arcLength(max, True) # 因为轮廓不是一个矩形,所以要近似为一个矩形
approx = cv2.approxPolyDP(max, epsilon, True)
res_shi = cv2.drawContours(tu1, [approx], -1, (0, 0, 255), 2)
xian(res_shi)
gray2 = cv2.cvtColor(res_shi, cv2.COLOR_BGR2GRAY) # 转灰然后进行角点检测
xian(gray2)
gray2 = np.float32(gray2)
dst = cv2.cornerHarris(gray2.copy(), 3, 3, 0.04)
dst = cv2.dilate(dst, None) # 因为后续要找角点的坐标,但角点很多又不连续,所以要膨胀一下
a = []
b = []
bk = np.zeros((h, w, 1), np.uint8) # 先创一张单通道空图,再进行阈值分割(这里也就是二值化)
bk[dst > 0.5 * dst.max()] = 255
thresh2 = cv2.threshold(bk, 127, 255, cv2.THRESH_BINARY)[1]
xian(thresh2)
contours2 = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0] # 获取轮廓信息后,进行轮廓中心计算得到每个轮廓中心的坐标
for i in contours2:
x, y, w, h = cv2.boundingRect(i)
m = cv2.moments(i)
cx = m['m10'] / m['m00']
cy = m['m01'] / m['m00']
a.append(cx)
b.append(cy)
print(a, b)
rows, cols, ch = res.shape # 这里我顺手写的,就不往上看了
pts1 = np.float32([[a[3], b[3]], [a[2], b[2]], [a[0], b[0]], [a[1], b[1]]]) # 获取原图ppt四个角的坐标
pts2 = np.float32([[0, 0], [cols, 0], [0, rows], [cols, rows]]) # 获取展示ppt变换投影后窗口四个角的坐标
M = cv2.getPerspectiveTransform(pts1, pts2) # 最后进行变换投影
dst = cv2.warpPerspective(img, M, (cols, rows))
xian(dst)
代码解析:
1、我们要获取ppt,首先要获取ppt的轮廓:
img = cv2.imread('D:\\picture\\dabo\\ppt.jpg') # 读图,因为图片太大要缩小
img = cv2.resize(img, None, fx=0.5, fy=0.5)
xian(img)
h, w, c = img.shape
gray1 = cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) # 先转灰,再二值化,最后找轮廓并画出
thresh1 = cv2.threshold(gray1, 175, 255, cv2.THRESH_BINARY)[1]
xian(thresh1)
contours1 = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0]
res_new = img.copy()
res = cv2.drawContours(res_new, contours1, -1, (0, 0, 255), 2)
xian(res)
2、面对这么多的轮廓,明显ppt的轮廓面积是最大的,所以我们用轮廓面积比较的方法来获取ppt的轮廓 :
max = contours1[0] # 找出面积最大的轮廓(ppt的轮廓)
for i in contours1:
if cv2.contourArea(i) > cv2.contourArea(max):
max = i
print(cv2.contourArea(max)) # 检查是不是大的
tu1 = np.zeros((h, w, c), np.uint8) # 用一张空图画出最大面积的轮廓(ppt的轮廓),方便以后找角点
res_goal = cv2.drawContours(tu1.copy(), max, -1, (0, 0, 255), 2)
xian(res_goal)
接着用一张空图来画出ppt的轮廓,后续要用
因为所得的轮廓不是一个矩形,所以要近似为一个矩形:
epsilon = 0.1 * cv2.arcLength(max, True) # 因为轮廓不是一个矩形,所以要近似为一个矩形
approx = cv2.approxPolyDP(max, epsilon, True)
res_shi = cv2.drawContours(tu1, [approx], -1, (0, 0, 255), 2)
xian(res_shi)
3、获取轮廓后,我们就可以角点检测了:
gray2 = cv2.cvtColor(res_shi, cv2.COLOR_BGR2GRAY) # 转灰然后进行角点检测
xian(gray2)
gray2 = np.float32(gray2)
dst = cv2.cornerHarris(gray2.copy(), 3, 3, 0.04)
dst = cv2.dilate(dst, None) # 因为后续要找角点的坐标,但角点很多又不连续,所以要膨胀一下
因为空图是黑色背景,用白点容易看。
因为我们要进行变换投影,所以要获取ppt四个角的坐标,而角点检测出来的点是很多的,所以我们要求四块角点们那一块的中点坐标:
a = []
b = []
bk = np.zeros((h, w, 1), np.uint8) # 先创一张单通道空图,再进行阈值分割(这里也就是二值化)
bk[dst > 0.5 * dst.max()] = 255
thresh2 = cv2.threshold(bk, 127, 255, cv2.THRESH_BINARY)[1]
xian(thresh2)
contours2 = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[0] # 获取轮廓信息后,进行轮廓中心计算得到每个轮廓中心的坐标
for i in contours2:
x, y, w, h = cv2.boundingRect(i)
m = cv2.moments(i)
cx = m['m10'] / m['m00']
cy = m['m01'] / m['m00']
a.append(cx)
b.append(cy)
print(a, b)
4、最后就是关键的变换投影了:
rows, cols, ch = res.shape # 这里我顺手写的,就不往上看了
pts1 = np.float32([[a[3], b[3]], [a[2], b[2]], [a[0], b[0]], [a[1], b[1]]]) # 获取原图ppt四个角的坐标
pts2 = np.float32([[0, 0], [cols, 0], [0, rows], [cols, rows]]) # 获取展示ppt变换投影后窗口四个角的坐标
M = cv2.getPerspectiveTransform(pts1, pts2) # 最后进行变换投影
dst = cv2.warpPerspective(img, M, (cols, rows))
xian(dst)
这是我第一次学习的结果,有些命名不是很专业,步骤也有些繁琐(可能有多余的),如果有更好的建议请在评论区留言。
本人第三次发帖,不喜勿喷。