当前位置:   article > 正文

使用python+opencv实现文档扫描_python opencv利用角点检测、边缘检测等,再通过投影变换完成对文档的对齐扫描

python opencv利用角点检测、边缘检测等,再通过投影变换完成对文档的对齐扫描

一、扫描文档的步骤

  • 捕获图像
  • 检测边缘
  • 提取所需对象/定义轮廓
  • 对提取的对象进行透视变换
  • 提取文本内容(此处不做处理)

1、scanner.py

  1. import cv2
  2. import numpy as np
  3. import rect
  4. #读入要检测的图片,此处读入单张图片。如果分辨率足够好的话,我们也可以使用笔记本电脑的摄像头。
  5. image = cv2.imread('test.jpg')
  6. #重新设置图片的大小,以便对其进行处理:选择最佳维度,以便重要内容不会丢失
  7. image = cv2.resize(image, (1500,880))
  8. #创建原始图像的副本
  9. orig = image.copy()
  10. #对图像进行灰度处理,并进而进行行高斯模糊处理
  11. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  12. blurred = cv2.GaussianBlur(gray, (5, 5), 0)
  13. #使用canny算法进行边缘检测
  14. edged = cv2.Canny(blurred,0,50)
  15. #创建canny算法处理后的副本
  16. orig_edged = edged.copy()
  17. #找到边缘图像中的轮廓,只保留最大的,并初始化屏幕轮廓
  18. #findContours()函数用于从二值图像中查找轮廓
  19. img, contours, hierarchy = cv2.findContours(edged, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
  20. #使用python中的sorted函数返回contours重新排序的结果(降序),排序规则(key):根据计算的轮廓面积大小
  21. contours = sorted(contours, key = cv2.contourArea, reverse = True)
  22. #得到近似轮廓
  23. for c in contours:
  24. p = cv2.arcLength(c, True) #计算封闭轮廓的周长或者曲线的长度
  25. approx = cv2.approxPolyDP(c, 0.02*p, True) #指定0.02*p精度逼近多边形曲线,这种近似曲线为闭合曲线,因此参数closed为True
  26. if len(approx) == 4: #如果逼近的是四边形
  27. target = approx #则此轮廓为要找的轮廓
  28. break #找到即跳出循环
  29. #将目标映射到800*800四边形
  30. approx = rect.rectify(target)
  31. pts2 = np.float32([[0,0],[800,0],[800,800],[0,800]])
  32. #透视变换
  33. # 使用gtePerspectiveTransform函数获得透视变换矩阵:approx是源图像中四边形的4个定点集合位置;pts2是目标图像的4个定点集合位置
  34. M = cv2.getPerspectiveTransform(approx, pts2)
  35. # 使用warpPerspective函数对源图像进行透视变换,输出图像dst大小为800*800
  36. dst = cv2.warpPerspective(orig, M, (800,800))
  37. #画出轮廓,-1表示所有的轮廓,画笔颜色为(0,255,0),粗细为2
  38. cv2.drawContours(image, [target], -1, (0, 255, 0), 2)
  39. #对透视变换后的图像进行灰度处理
  40. dst = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
  41. #对透视变换后的图像使用阈值进行约束获得扫描结果
  42. # 使用固定阈值操作:threshold()函数:有四个参数:第一个是原图像,第二个是进行分类的阈值,第三个是高于(低于)阈值时赋予的新值,
  43. # 第四个是一个方法选择参数:cv2.THRESH_BINARY(黑白二值)
  44. # 该函数返回值有两个参数,第一个是retVal(得到的阈值值(在OTSU会用到)),第二个是阈值化后的图像
  45. ret, th1 = cv2.threshold(dst, 127, 255, cv2.THRESH_BINARY) #进行固定阈值处理,得到二值图像
  46. # 使用Otsu's二值化,在最后一个参数加上cv2.THRESH_OTSU
  47. ret2, th2 = cv2.threshold(dst, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
  48. # 使用自适应阈值操作:adaptiveThreshold()函数
  49. # 第二个参数为领域内均值,第五个参数为规定正方形领域大小(11*11),第六个参数是常数C:阈值等于均值减去这个常数
  50. th3 = cv2.adaptiveThreshold(dst, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
  51. # 第二个参数为领域内像素点加权和,权重为一个高斯窗口,第五个参数为规定正方形领域大小(11*11),第六个参数是常数C:阈值等于加权值减去这个常数
  52. th4 = cv2.adaptiveThreshold(dst,255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
  53. #输出处理后的图像
  54. cv2.imshow("原始图像", orig)
  55. cv2.imshow("原始图像经灰度变换", gray)
  56. cv2.imshow("原始图像经高斯模糊处理", blurred)
  57. cv2.imshow("原始图像经canny边缘检测后的结果", orig_edged)
  58. cv2.imshow("边界被标记的原图", image)
  59. cv2.imshow("固定阈值操作", th1)
  60. cv2.imshow("Otsu二值化", th2)
  61. cv2.imshow("自适应阈值(领域内均值)", th3)
  62. cv2.imshow("自适应阈值(领域内像素点加权和)", th4)
  63. cv2.imshow("透视变换后的图像", dst)
  64. cv2.waitKey(0)
  65. cv2.destroyAllWindows()

2、rect.py

  1. import numpy as np
  2. def rectify(h):
  3. h = h.reshape((4,2)) #改变数组的形状,变成4*2形状的数组
  4. hnew = np.zeros((4,2), dtype = np.float32) #创建一个4*2的零矩阵
  5. #确定检测文档的四个顶点
  6. add = h.sum(1)
  7. hnew[0] = h[np.argmin(add)] #argmin()函数是返回最大数的索引
  8. hnew[2] = h[np.argmax(add)]
  9. diff = np.diff(h, axis = 1) #沿着制定轴计算第N维的离散差值
  10. hnew[1] = h[np.argmin(diff)]
  11. hnew[3] = h[np.argmax(diff)]
  12. return hnew

 

注意:在程序调试时出现以下错误---ValueError: too many values to unpack (expected 2)

此错误说明是函数输出的值没有足够的参数对其进行存储,即变量个数不够

                  

是因为在python2和python3中,cv2.findContours():

                                   python2中会返回两个值:contours, hierarchy

                                   python三中会返回三个值:img, contours, hierarchy

  1. #findContours()函数用于从二值图像中查找轮廓
  2. #python2
  3. contours, hierarchy = cv2.findContours(edged, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
  4. #python3
  5. img, contours, hierarchy = cv2.findContours(edged, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

 

3、结果

  • 原始图片

  • 原始图像经灰度变换

  • 原始图像经过高斯模糊

  • 原始图像经Canny边缘检测

  • 固定阈值操作

 

  • Otsu二值化

 

  • 自适应阈值(领域内均值)

 

  • 自适应阈值(领域内像素点加权和)

  • 边界被标记的原图

 

  • 经透视变换后的扫描文档

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/599492
推荐阅读
相关标签
  

闽ICP备14008679号