稍微整理了一下这个系列的一二三四章,可能看着更舒服吧……这个系列的解决方案不止一种,调参的方法也是各种各样,反正能够满足需求就极好了

1.预处理

这次的机读卡识别项目来源暑期培训,主要包括内容一张手机拍摄的机读卡位置定位,识别其中选择题模块及少量数字识别,给出样例图片:

预处理目的:

对于这个识别问题而言,把图像变成二值图应该是最简单粗暴的方法了。为了找准边界,才能良好切割。而对于边缘检测的函数也只能传入灰度图……

1.1.环境配置:

环境是python3.5的,大体部分需要配置的是numpy+mlk版本,scipy,来支持opencv,另外辅助以imutils,这个包里面含有4点变换函数以及matplotlib来辅助绘图

import cv2

import matplotlib.pyplot as plt

import imutils

from imutils.perspective import four_point_transform

1.2.图片预处理

为了方便找出图片的4个顶点,所以需要一次自适应二值化,为了使图片效果更好,所以在二值化之前还加了一层高斯滤波

#读入图片

image = cv2.imread("test10.jpg")

#转换为灰度图像

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#高斯滤波

blurred = cv2.GaussianBlur(gray, (3, 3), 0)

#自适应二值化方法

blurred=cv2.adaptiveThreshold(blurred,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,51,2)

'''

adaptiveThreshold函数:第一个参数src指原图像,原图像应该是灰度图。

第二个参数x指当像素值高于(有时是小于)阈值时应该被赋予的新的像素值

第三个参数adaptive_method 指: CV_ADAPTIVE_THRESH_MEAN_C 或 CV_ADAPTIVE_THRESH_GAUSSIAN_C

第四个参数threshold_type  指取阈值类型:必须是下者之一

•  CV_THRESH_BINARY,

• CV_THRESH_BINARY_INV

第五个参数 block_size 指用来计算阈值的象素邻域大小: 3, 5, 7, ...

第六个参数param1    指与方法有关的参数。对方法CV_ADAPTIVE_THRESH_MEAN_C 和 CV_ADAPTIVE_THRESH_GAUSSIAN_C, 它是一个从均值或加权均值提取的常数, 尽管它可以是负数。

'''

#这一步可有可无,主要是增加一圈白框,以免刚好卷子边框压线后期边缘检测无果。好的样本图就不用考虑这种问题

blurred=cv2.copyMakeBorder(blurred,5,5,5,5,cv2.BORDER_CONSTANT,value=(255,255,255))

2.图像切割

图像切割的目的是将图像定个便于识别的样子。比如这里四角变换结束以后会吧图像变为2400*2800的大小,无论是什么样的案例图片,都是这个格式,这样最后在局部分割,如选择题答案的识别和数字区域的确定这套程序才能有较好的通用性

2.1.边缘检测

预处理得到二值图像就很容易做边缘检测了,找出4个点,方便之后的4点变换

#canny边缘检测

edged = cv2.Canny(blurred, 10, 100)

# 从边缘图中寻找轮廓,然后初始化答题卡对应的轮廓

'''

findContours

image -- 要查找轮廓的原图像

mode -- 轮廓的检索模式,它有四种模式:

cv2.RETR_EXTERNAL  表示只检测外轮廓

cv2.RETR_LIST 检测的轮廓不建立等级关系

cv2.RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,

这个物体的边界也在顶层。

cv2.RETR_TREE 建立一个等级树结构的轮廓。

method --  轮廓的近似办法:

cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max (abs (x1 - x2), abs(y2 - y1) == 1

cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需

4个点来保存轮廓信息

cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

'''

cnts = cv2.findContours(edged, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

cnts = cnts[0] if imutils.is_cv2() else cnts[1]

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

顶点坐标的存放形式为3维数组,所以若想演示最大的4个顶点应做如下操作:

newimage=image.copy()

for i in docCnt:

#circle函数为在图像上作图,新建了一个图像用来演示四角选取

cv2.circle(newimage, (i[0][0],i[0][1]), 50, (255, 0, 0), -1)

2.2.四点变换

四点变换直接调用大佬写好放在imutils中的函数就好了。这里存了两个,一个原图一个灰度图,原图用来配合展示,灰度图用来支配

paper = four_point_transform(image, docCnt.reshape(4, 2))

warped = four_point_transform(gray, docCnt.reshape(4, 2))

3.对选择题识别

3.1.对选择题图像部分预处理

经过四点变换后的图像需要经过重新转换标准长宽,以便对选择题部分标定题号及答案。这里的图像定义为2400*2800 。选择题部分最大的特点是需要将黑块突出,以及过滤掉没填涂的选项,以便确认。预处理方法选择均值滤波及二进制二值化的方法。

# 对灰度图应用二值化算法

thresh=cv2.adaptiveThreshold(warped,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,53,2)

#重塑可能用到的图像

thresh = cv2.resize(thresh, (width1, height1), cv2.INTER_LANCZOS4)

paper = cv2.resize(paper, (width1, height1), cv2.INTER_LANCZOS4)

warped = cv2.resize(warped, (width1, height1), cv2.INTER_LANCZOS4)

#均值滤波

ChQImg = cv2.blur(thresh, (23, 23))

#二进制二值化

ChQImg = cv2.threshold(ChQImg, 100, 225, cv2.THRESH_BINARY)[1]

'''

threshold参数说明

第一个参数 src    指原图像,原图像应该是灰度图。

第二个参数 x     指用来对像素值进行分类的阈值。

第三个参数 y     指当像素值高于(有时是小于)阈值时应该被赋予的新的像素值

第四个参数 Methods 指,不同的不同的阈值方法,这些方法包括:

•cv2.THRESH_BINARY

•cv2.THRESH_BINARY_INV

•cv2.THRESH_TRUNC

•cv2.THRESH_TOZERO

•cv2.THRESH_TOZERO_INV

'''

3.2.寻找结果中黑块坐标

这里寻找坐标的目的是为了确定黑块所代表的题号及选项,用轮廓中心来进行描述

# 在二值图像中查找轮廓

cnts = cv2.findContours(ChQImg, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cnts = cnts[0] if imutils.is_cv2() else cnts[1]

for c in cnts:

# 计算轮廓的边界框,然后利用边界框数据计算宽高比

(x, y, w, h) = cv2.boundingRect(c)

if (w > 60 & h > 20)and y>900 and y<2000:

M = cv2.moments(c)

cX = int(M["m10"] / M["m00"])

cY = int(M["m01"] / M["m00"])

#绘制中心及其轮廓

cv2.drawContours(paper, c, -1, (0, 0, 255), 5, lineType=0)

cv2.circle(paper, (cX, cY), 7, (255, 255, 255), -1)

#保存题目坐标信息

Answer.append((cX, cY))

3.3.计算选择题题号及答案

比较绕,主要还是根据取余和倍数关系

def judgey0(y):

if (y / 5 < 1):

return y + 1

elif y / 5 < 2 and y/5>=1:

return y % 5 + 20 + 1

else:

return y % 5 + 40 + 1

def judgex0(x):

if(x%5==1):

return 'A'

elif(x%5==2):

return 'B'

elif(x%5==3):

return 'C'

elif(x%5==4):

return 'D'

def judge0(x,y):

if x/5<1 :

#print(judgey0(y))

return (judgey0(y),judgex0(x))

elif x/5<2 and x/5>=1:

#print(judgey0(y)+5)

return (judgey0(y)+5,judgex0(x))

elif x/5<3 and x/5>=2:

# print(judgey0(y)+10)

return (judgey0(y)+10,judgex0(x))

else:

#print(judgey0(y)+15)

return (judgey0(y)+15,judgex0(x))

输出运算结果:

IDAnswer=[]

for i in Answer:

for j in range(0,len(xt1)-1):

if i[0]>xt1[j] and i[0]

for k in range(0,len(yt1)-1):

if i[1]>yt1[k] and i[1]

judge0(j,k)

IDAnswer.append(judge0(j,k))

#对答案部分重新排序,以最好的方式输出

IDAnswer.sort()

print(IDAnswer)

print(len(IDAnswer))

至此完成选择题部分

4.数字识别,调用百度api

数字识别经过测试总的感觉还是可以。需要注意的地方是要对数字板块需要切割出来这样给机器会好认点,但也不能单个字拿出来。最好能有一串,同时也需要注意图片尺寸

4.1.对数字图像部分进行处理

预处理部分同样需要,步骤与选择题模块相似,但目的不同,文字部分主要将数字变粗,便于识别。其实也就是和选择题模块相比变了几个参数

NumImg=cv2.blur(thresh,(15,15))

NumImg=cv2.threshold(NumImg, 170, 255, cv2.THRESH_BINARY)[1]

4.2.调用百度ocr api

试过多种检测方式,还是用别人家现成的好http://apistore.baidu.com/

百度api使用方法:

首先需要注册一个百度云账号,这样在个人中心里就会看到apikey。这个就是和百度进行交流的钥匙。然后找到百度ocr的入口找到接口地址。虽然这里给出了但还是可以看下文档,里面有些细节,比如图片想免费就要300k以内。上面给的python示例代码是py2的,这里给出py3的方式(http://apis.baidu.com/idl_baidu/baiduocrpay/idlocrpaid)

import sys, urllib, json

import urllib.request

import urllib.parse

import base64

url = 'http://apis.baidu.com/idl_baidu/ocridcard/ocridcard'

data = {}

data['fromdevice'] = "pc"

data['clientip'] = "10.10.10.0"

data['detecttype'] = "LocateRecognize"

data['languagetype'] = "ENG"#英文模式

data['imagetype'] = "1"

#图片在本地

file_object = open('T.png','rb')

try:

img = file_object.read( )

finally:

file_object.close( )

data['image'] =base64.b64encode(img)

decoded_data = urllib.parse.urlencode(data)

decoded_data = decoded_data.encode('utf-8')

req = urllib.request.Request(url,decoded_data)

req.add_header("Content-Type", "application/x-www-form-urlencoded")

req.add_header("apikey", "这里填入个人中心的apikey")

resp = urllib.request.urlopen(req)

content = resp.read()

if(content):

content = json.loads(content.decode())

print(content)

4.3.切割图片

根据具体情况需要切割图片才能让百度api识别,具体限制因素还是图片大小,切割方式,这里只给出示例

#切割具体位置[起始y:终止y,起始x:终止y]

tempimg1=img[240:461,213:939]

#图片切割,width,height分别填入目标宽高

tempimg1 = cv2.resize(tempimg1, (width, height), cv2.INTER_LANCZOS4)

#图片保存,png,jpg格式均可

cv2.imwrite("T.png", tempimg1)

之后调用,若识别为英文需要转化,比如可能将0识别为D,这时转换即可,如:

def temp(char):

if(char=='D'):

return '0'

效果如图展示

当然若是能想办法去掉答题卡外围边框效果应该会更好……

python 答题卡识别_opencv+python机读卡识别整合版相关推荐

  1. python 答题卡识别_opencv+python机读卡识别(初级版)

    最近在进一步学习Python,在网上发现有使用opencv进行机读卡识别的, 就根据大神的文章,跟着学习,自己写了一个机读卡识别, 文章一:opencv+python机读卡识别整合版 文章二:pyth ...

  2. python 答题卡识别_opencv+python机读卡识别(最终版)

    本文是对之前编写的机读卡进行完善, 只记录相关代码,不介绍具体编写流程, 具体流程:opencv+python机读卡识别(进阶版) 完善相关机读卡的适配,记录相关调试函数以及使用方法. # -*- c ...

  3. python识别图像数字诊断模块_opencv+python 机读卡识别

    长按上图识别二维码报名济南源创会 摘要: 通过随意一张机读卡的照片,识别其中选择题题号,选项,以及相关数字识别.这个系列的解决方案不止一种,调参的方法也是各种各样,反正能够满足需求就极好了 1.预处理 ...

  4. opencv+python机读卡识别

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 1.预处理 这次的机读卡识别项目来源暑期培训,主要包括内容一张手机拍摄的机读卡位置定位,识别其 ...

  5. opencv+python机读卡识别(一)预处理

    2019独角兽企业重金招聘Python工程师标准>>> 第二部分图像切割:https://my.oschina.net/u/3268732/blog/1236344 第三部分选择题识 ...

  6. 基于OpenCV的简单机读卡识别

    文章目录 一.简单介绍 二.步骤回顾 2.1 图像处理 2.1.1 图像的二值化 2.1.2 ROI(region of interest,感兴趣区域)的分割 a. 选择题部分分割 b. 数字部分分割 ...

  7. OpenCV机读卡识别

    简单介绍 编写一个基于OpenCV的小程序,用于识别下图所示机读卡. 步骤回顾 图像处理 图像二值化 图像识别离不开图像的处理.用相机拍摄的机读卡基本都是三通道的彩色图像,而这里需要用到的处理方法就是 ...

  8. 用计算机过去机读卡,阅卷机读卡机答题卡使用流程

    0603SJX阅卷机读卡机答题卡使用流程 云微阅卷机光标阅读机简介 光标阅读机,是用光学扫描的方法来识别按***格式印刷或书写的标记,并将其转换为计算机能接受的电信号的设备.作为一种新的计算机外设,它 ...

  9. python车牌字符分割_OpenCV+Python识别车牌和字符分割的实现

    本篇文章主要基于python语言和OpenCV库(cv2)进行车牌区域识别和字符分割,开篇之前针对在python中安装opencv的环境这里不做介绍,可以自行安装配置! 车牌号检测需要大致分为四个部分 ...

最新文章

  1. python常用模块实例_python中常用的各种数据库操作模块和连接实例
  2. Ubuntu安装HBase2.2.4并进行单机/伪分布式配置
  3. 运算符--位移运算符和一些其他运算符
  4. Grafana密码重置为admin
  5. html绘制流程图飞线,基于jsplumb绘制流程图
  6. 高性能web系统的架构和系统优化
  7. JZOJ 3517. 空间航行
  8. perl语言数据类型
  9. 讲座笔记:图匹配 Graph Matching 问题 | 机器学习组合优化
  10. Python基础(作用域)
  11. 完全卸载惠普打印机驱动程序方法搜集(未验证)
  12. ECharts 实现地图功能
  13. 怎么在Excel里输入可以打钩的选择框?
  14. 生物什么时候学公式计算机,高考生物重要规律性关系及公式精华归纳,转走吧...
  15. 用python实现多人聊天室小项目笔记
  16. java筆試題,Java筆試題附答案 | 學步園
  17. MATLAB连接USRP
  18. 2022上半年系统集成项目管理师客观题参考答题解析(1)
  19. nobup 与 后台运行命令
  20. uni-app中使用uniCloud实现发送短信验证码(开通、配置、使用)

热门文章

  1. 动态生成网站地图sitemap.xml
  2. 图片不变形,按照等比例缩小或扩大显示
  3. AD19 网络标签 无法连接
  4. 远程 PC 访问软件
  5. 暗影精灵4清灰、加硅脂
  6. 聚合数据+新闻头条+数据入库+数据展示
  7. CSS实现文字竖向排列
  8. matlab图形黎曼几何,张思容
  9. Linux 性能监控分析
  10. js--动态生成表格