OpenCV实战之文档扫描判卷
import cv2
import numpy as np #图像显示
def cv_show(imgname,img):
cv2.imshow(imgname,img)
cv2.waitKey(0)
cv2.destroyAllWindows() #排序坐标函数
def order_pts(pts):
rect=np.zeros((4,2),dtype='float32') s = np.sum(pts,axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
n = np.diff(pts,axis=1)
rect[1] = pts[np.argmin(n)]
rect[3] = pts[np.argmax(n)] return rect #透视变换
def four_pts_change(img,pts):
points = order_pts(pts)
(tl,tr,bl,br) = points widthA = np.sqrt(((tr[1]-tl[1])**2)+((tr[0]-tl[0])**2))
widthB = np.sqrt(((br[1] - bl[1]) ** 2) + ((br[0] - bl[0]) ** 2))
width = max(int(widthA),int(widthB)) lengthA = np.sqrt(((tr[1]-br[1])**2)+((tr[0]-br[0])**2))
lengthB = np.sqrt(((tl[1] - bl[1]) ** 2) + ((tl[0] - bl[0]) ** 2))
length = max(int(lengthA),int(lengthB)) #输出图坐标
dst = np.array([
(0,0),
(width-1,0),
(width-1,length-1),
(0,length)
],dtype='float32') M = cv2.getPerspectiveTransform(points,dst)
wraped = cv2.warpPerspective(img,M,(width,length))
return wraped
#正确答案
ANSWER_KEY={0:1,1:4,2:0,3:3,4:1}
# ANSWER_KEY = {0:1,1:3,2:0,3:4,4:1} img = cv2.imread('./textcard.png')
cv_show('img',img)
orig = img.copy()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#高斯模糊
gaussian = cv2.GaussianBlur(gray,(3,3),0)
cv_show('gaussian',gaussian)
#边缘检测
canny = cv2.Canny(gaussian,70,150)
cv_show('canny',canny)
#轮廓检测
cnts = cv2.findContours(canny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
cnts = sorted(cnts,key=cv2.contourArea,reverse=True)
# cv2.drawContours(orig,cnts,-1,(149,32,190),2)
# cv_show('orig',orig)
for i in cnts:
perix = cv2.arcLength(i,True)
approx = cv2.approxPolyDP(i,0.01*perix,True)
if len(approx)==4:
screen = approx
break
cv2.drawContours(orig,[screen],-1,(149,32,190),2)
# cv_show('orig',orig)
#透视变换
wraped = four_pts_change(img,screen.reshape(4,2))
cv_show('wraped',wraped)
wraped_gray = cv2.cvtColor(wraped,cv2.COLOR_BGR2GRAY)
#阈值处理
thresh = cv2.threshold(wraped_gray,0,255,cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh) #检测轮廓
thresh_cnts=thresh.copy()
cnts1 = cv2.findContours(thresh_cnts,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
#白色填充轮廓
cv2.drawContours(thresh_cnts,cnts1,-1,(0,0,0),3)
cv_show('WRAPED',thresh_cnts)
#检测圆形
questions = []
for cnt in cnts1:
(x,y,w,h) = cv2.boundingRect(cnt)
# print((x,y,w,h))
arc = w/float(h)
if w>20 and h>20 and arc >0.6 and arc<1.1:
questions.append(cnt)
print('一共有{}个选项'.format(len(questions)))
# print(questions) #从上到下排序
boundingBox =[ cv2.boundingRect(i) for i in questions]
(questionCnts,boundingBox) = zip(*sorted(zip(questions,boundingBox),key=lambda b:b[1][1],reverse=False)) correct =0
#每行遍历
for (i,c) in enumerate(np.arange(0,len(questions),5)): #遍历每一行的第一个 返回值是[(1,0),(2,5),(3,10),(4,15),(5,20)]
boundingBox = [cv2.boundingRect(a) for a in questionCnts[c:c+5]] #框出每一行的每个圆
(cnts,boundingBox) = zip(*sorted(zip(questionCnts[c:c+5],boundingBox),key=lambda b:b[1][0],reverse=False)) #每一行的圆的轮廓和框框按从左到右的顺序排列
bubble = None
for (j,q) in enumerate(cnts):
mask = np.zeros_like(thresh)
cv2.drawContours(mask,[q],-1,255,-1) #白色填充圆
# cv_show('mask', mask)
mask = cv2.bitwise_and(thresh,thresh,mask=mask) #抠出每一个选项
# cv_show('mask',mask)
total = cv2.countNonZero(mask)
if bubble is None or total>bubble[0]:
bubble = (total,j)
k = ANSWER_KEY[i]
if k == bubble[1]:
correct +=1 score = (correct/5)*100
print('[INFO]score : {:.2f}%'.format(score))
cv2.putText(wraped,'{:.2f}%'.format(score),(10,30),cv2.FONT_HERSHEY_SIMPLEX,0.9,(123,123,123),2)
cv_show('score',wraped)
OpenCV实战之文档扫描判卷的更多相关文章
- 深入学习OpenCV文档扫描及OCR识别(文档扫描,图像矫正,透视变换,OCR识别)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice 下面 ...
- [实战]MVC5+EF6+MySql企业网盘实战(23)——文档列表
写在前面 上篇文章实现了图片列表,这篇文章实现文档列表将轻车熟路,因为逻辑基本相似,只是查询条件的不同.这里将txt,doc,docx,ppt,pptx,xls,xlsx的文件都归为文档列表中. 系列 ...
- JavaEE实战——XML文档DOM、SAX、STAX解析方式详解
原 JavaEE实战--XML文档DOM.SAX.STAX解析方式详解 2016年06月22日 23:10:35 李春春_ 阅读数:3445 标签: DOMSAXSTAXJAXPXML Pull 更多 ...
- 分布式架构--Dubbo项目实战学习文档
安装Dubbo注册中心(Zookeeper-3.4.6) 安装Dubbo管理控制台 Tomcat中部署web应用 ---- Dubbo服务消费者Web应用war包的部署 Dubbo监控中心的介绍与简易 ...
- Hapi+MySql项目实战自动化文档生成(四)
自动化生成swagger文档 使用hapi插件hapi-swagger,简单配置下插件,先修改下plugin_config.js文件: //plugin_config.js const Swagger ...
- 工程师泄露5G核心技术文档 被判有期徒刑三年缓刑四年
2002 年至 2017 年 1 月,黄某瑜就职于中兴通讯公司,担任过射频工程师.无线架构师等职务.2008 年 4 月至 2016 年 10 月,王某就职于中兴通讯公司西安研究所,担任过 RRU 部 ...
- Node.js+Web TWAIN,实现Web文档扫描和图像上传
目录(?)[+] 通过Dynamic Web TWAIN SDK和Node.js的组合,只需要几行代码就可以实现在浏览器中控制扫描仪,获取图像后上传到远程服务器. 原文:Document Imag ...
- Sping源码+Redis+Nginx+MySQL等七篇实战技术文档,阿里大佬推荐
JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. 引入 ...
- 编译OpenCV文档
概述 使用OpenCV的过程中经常查看文档,每次都去官网查看,不过国内访问速度很慢,有一份本地的文档就好了.本文列出了在Linux(Fedora)系统上从OpenCV源码编译出documentatio ...
- opencv 离线文档下载地址在哪里?
OpenCV 官方离线文档下载地址:http://docs.opencv.org/ 如何生成离线文档? http://docs.opencv.org/master/d4/db1/tutorial_do ...
随机推荐
- Jupyter notebook upload无法加载本地ipynb文件
可能是本地浏览器(IE)问题,修改默认浏览器.
- CCF-CSP准备
dfs序,unique vector sort(que+1,que+1+cnt); len = unique(que+1,que+cnt+1)-que-1; for(int i = 1;i <= ...
- Spring不同版本的AOP
1.Spring4.SpringBoot1 1.1 代码实现 public interface Calculator { int div(int a,int b); } @Component publ ...
- ASR6601:国产化lora SOC芯片兼容SX1262/SX1268
ASR6601为目前首颗国产化支持LoRaWAN低功耗广域网无线通信SoC芯片.ASR6601在单芯片上集成了通用微控制器和射频单元(SX1262),包括射频收发器,调制解调器和48 MHz 主频.A ...
- reduce()
from functools import reducea=[10,11,22,33]b=reduce(lambda x,y:x+y,a)<===>sum(a)print(b)
- 关于 dangerouslySetInnerHTML
之前不太了解react,第一次看dangerouslySetInnerHTML,以为可以用来防止xss注入. 后面看待又补充了一个DOMPurify,才知道这个东西只有一个提醒的作用,并不能防止xss ...
- [Oracle19C ASM管理] ASM服务的启停
自动方式启停 crsctl stat res -t 查看ASM服务的状态,it's ok that ora.ons和ora.diskmon是OFFLINE [grid@centos7-19c.loca ...
- HTML基本介绍与操作
一,HTML介绍 HTML,全称是超文本标记语言(HyperText Markup Language),它是一种用于创建网页的标记语言.标记语言是一种将文本(Text)以及文本相关的其他信息结合起来, ...
- pip安装清华源
一.更换PIP源PIP源在国外,速度慢,可以更换为国内源,以下是国内一些常用的PIP源. 豆瓣(douban) http://pypi.douban.com/simple/ (推荐)清华大学 http ...
- DevExpress 动态换肤
我们都知道Devexpress内置了很多themes,那要怎么在使用时动态更改呢. 下面是方法以: 1.如果你们已经有主题了,那就在XAML中删除类似下下面的语句. dx:ThemeManager.T ...