opencv-python 中获取PPT投影变换后的图象

话不多说直接上代码:

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)

95b01735d34c4d5e949b98ca20f80ce1.png

 

代码解析:

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)

93cdb775084c4e0cab815f0fcd7d97f9.png

 66bff853ccff475ebc2c427d4d268a53.png

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的轮廓,后续要用

19a2f8f3b33e4c49aa00a0b9eb00cb40.png

 因为所得的轮廓不是一个矩形,所以要近似为一个矩形:

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)

9b427f288caa42019f4c972a4fbb86e4.png

 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) # 因为后续要找角点的坐标,但角点很多又不连续,所以要膨胀一下

f1aa81a733e24489b3006afe6668161d.png

60f690cf06054130842a1c4125ed481c.png

因为空图是黑色背景,用白点容易看。

因为我们要进行变换投影,所以要获取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)

27ccc581be1d4faeaeac8f1bef7a7d37.png

 这是我第一次学习的结果,有些命名不是很专业,步骤也有些繁琐(可能有多余的),如果有更好的建议请在评论区留言。

本人第三次发帖,不喜勿喷。

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值