Python实现校园卡目标检测与文字识别系统

百家 作者:AI100 2021-03-01 18:21:28

引言:本项目主要从两方面出发,一是搭建目标检测系统,利用hog+svm的方法,从网络摄像头读取数据,目标检测找出校园卡的位置;二是在找到校园卡位置后,保存下单独校园卡图片,然后进行图像处理,找到关键文字位置,利用百度文字识别进行提取文字信息。

作者 |?李秋键

责编?|?寇雪芹

头图 | 下载于视觉中国



校园卡目标检测

1.1 环境要求
本次环境使用的是python3.6.5+windows平台,主要用的库是图像处理库opencv,包括用来目标检测和图像处理等操作。
1.2 数据集处理
其中数据集由自己利用手机摄像头拍照获得,因为要使用的分类算的是SVM算法,故需要定义两种类别,一种是需要寻找的目标图片,即校园卡图片存储在positive文件夹下,如图1可见;第二种类别是干扰的其它图片,存放在negative文件夹下,如图2所示。
图1?positive文件夹数据集 ?
图2 negative文件夹数据集
通过os模块加载本地文件夹中的图片,分别以pos_dir,neg_dir和test_dir变量用来存储正样本数据、负样本数据和测试集数据。具体代码如下:
1pwd?=?os.getcwd()
2logger.info('Current?path?is:{}'.format(pwd))
3#?提取正样本
4pos_dir?=?os.path.join(pwd,?'Positive')
5if?os.path.exists(pos_dir):
6????logger.info('Positive?data?path?is:{}'.format(pos_dir))
7????pos?=?os.listdir(pos_dir)
8????logger.info('Positive?samples?number:{}'.format(len(pos)))
9#?提取负样本
10neg_dir?=?os.path.join(pwd,?'Negative')
11if?os.path.exists(neg_dir):
12????logger.info('Negative?data?path?is:{}'.format(neg_dir))
13????neg?=?os.listdir(neg_dir)
14????logger.info('Negative?samples?number:{}'.format(len(neg)))
15#?提取测试集
16test_dir?=?os.path.join(pwd,?'TestData')
17if?os.path.exists(test_dir):
18????logger.info('Test?data?path?is:{}'.format(test_dir))
19????test?=?os.listdir(test_dir)
20????logger.info('Test?samples?number:{}'.format(len(test)))

其中训练的数据需要将训练集和测试室合在一起,同时定义标签数组与之对应,即属于正样本时标签就是为1;属于负样本数据时标签就是变为-1。
具体代码如下:
1pwd?=?os.getcwd()
2pos_dir?=?os.path.join(pwd,?'Positive')
3neg_dir?=?os.path.join(pwd,?'Negative')
4samples?=?[]
5labels?=?[]
6for?f?in?pos:
7????file_path?=?os.path.join(pos_dir,?f)
8????if?os.path.exists(file_path):
9????????samples.append(file_path)
10????????labels.append(1.)
11for?f?in?neg:
12????file_path?=?os.path.join(neg_dir,?f)
13????if?os.path.exists(file_path):
14????????samples.append(file_path)
15????????labels.append(-1.)
16#?labels?要转换成numpy数组,类型为np.int32
17labels?=?np.int32(labels)
18labels_len?=?len(pos)?+?len(neg)
19labels?=?np.resize(labels,?(labels_len,?1))

1.3 特征提取
其中特征的提取主要通过从训练数据集中提取HOG特征作为训练特征,其中函数HOGDescriptor一共有4个构造函数,其中分别是参数winSize(64,128), blockSize(16,16), blockStride(8,8), cellSize(8,8), nbins(9)。这些都是HOGDescriptor的成员变量,括号里的数值是它们的默认值,它们反应了HOG描述子的参数。其中winSize指的是窗口大小 ,blockSize指的是块大小 ,cellSize指的是胞元大小 ,nbins指的是梯度方向数,nBins表示在一个胞元(cell)中统计梯度的方向数目,例如nBins=9时,在一个胞元内统计9个方向的梯度直方图,每个方向为180/9=20度。
具体代码如下:
1train?=?[]
2logger.info('Extracting?HOG?Descriptors...')
3num?=?0.
4total?=?len(samples)
5for?f?in?samples:
6????num?+=?1.
7????logger.info('Processing?{}?{:2.1f}%'.format(f,?num/total*100))
8????hog?=?cv2.HOGDescriptor((64,128),?(16,16),?(8,8),?(8,8),?9)
9????#?hog?=?cv2.HOGDescriptor()
10????img?=?cv2.imread(f,?-1)
11????img?=?cv2.resize(img,?(64,128))
12????descriptors?=?hog.compute(img)
13????logger.info('hog?feature?descriptor?size:?{}'.format(descriptors.shape))????#?(3780,?1)
14????train.append(descriptors)
15train?=?np.float32(train)
16train?=?np.resize(train,?(total,?3780))

1.4 SVM分类
通过使用SVM函数cv2.ml.SVM_create()建立SVM分类器,其中所使用的核函数为cv2.ml.SVM_LINEAR线性核函数。并在训练完成后保存成svm模型。?
图3?不同SVM对比效果
代码如下:
1logger.info('Configuring?SVM?classifier.')
2svm?=?cv2.ml.SVM_create()
3svm.setCoef0(0.0)
4svm.setDegree(3)
5criteria?=?(cv2.TERM_CRITERIA_MAX_ITER?+?cv2.TERM_CRITERIA_EPS,?1000,?1e-3)
6svm.setTermCriteria(criteria)
7svm.setGamma(0)
8svm.setKernel(cv2.ml.SVM_LINEAR)
9svm.setNu(0.5)
10svm.setP(0.1)??#?for?EPSILON_SVR,?epsilon?in?loss?function?
11svm.setC(0.01)??#?From?paper,?soft?classifier
12svm.setType(cv2.ml.SVM_EPS_SVR)
13logger.info('Starting?training?svm.')
14svm.train(train,?cv2.ml.ROW_SAMPLE,?labels)
15logger.info('Training?done.')
16pwd?=?os.getcwd()
17model_path?=?os.path.join(pwd,?'svm.xml')
18svm.save(model_path)
19logger.info('Trained?SVM?classifier?is?saved?as:?{}'.format(model_path))
20


1.5 模型测试
通过IP摄像头读入数据,然后利用模型检测输入的视频流。
1hog?=?cv2.HOGDescriptor()
2hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
3pwd?=?os.getcwd()
4test_dir?=?os.path.join(pwd,?'TestData')
5cap=cv2.VideoCapture("http://admin:admin@192.168.137.124:8081/")
6while?True:
7????_,?frame?=?cap.read()
8????rects,?_?=?hog.detectMultiScale(frame,?winStride=(4,?4),?padding=(8,?8),?scale=1.05)
9????for?(x,?y,?w,?h)?in?rects:
10????????cv2.rectangle(frame,?(x,?y),?(x?+?w,?y?+?h),?(0,?0,?255),?2)
11????cv2.imshow('Detect',?frame)
12????c?=?cv2.waitKey(1)?&?0xff
13????if?c?==?27:
14????????break
最终达成的测试效果如下图所见:?
图4?模型测试效果图

校园卡信息提取

在得到视频检测到校园卡的位置之后,对校园卡进行图像处理操作。
操作流程如下可见:
(1)读入图片,并设定成一定尺寸
1img=cv2.imread("TestData/0.jpg")
2img=cv2.resize(img,(400,300))
(2)初始化几个结构化内核,构造了两个这样的内核 - 一个矩形和一个正方形。我们将使用矩形的一个用于Top-hat形态运算符,将方形一个用于关闭操作。
1rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(12,12))
2sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
3)将图片就行灰度化操作,然后执行Top-hat形态操作,将结果存储为?tophat,Top-hat操作显示了深色背景下的亮区。
1gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
2#执行Top-hat形态操作,将结果存储为?tophat,Top-hat操作显示了深色背景下的亮区
3tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
(4)计算沿x方向的渐变在计算gradX ??数组中每个元素的绝对值之后 ,我们采取一些步骤将值缩放到范围[0-255](因为图像当前是浮点数据类型)。要做到这一点,我们计算 MINVAL和 MAXVAL的gradX,然后由我们的缩放方程上显示(即,最小/最大归一化)。最后一步是将gradX转换为 uint8,其范围为[0-255]。然后执行gradX 图像的Otsu和二进制阈值,然后是另一个关闭操作,对数字分段
1gradx=cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1)
2gradx=np.absolute(gradx)
3(minval,maxval)=(np.min(gradx),np.max(gradx))
4gradx=(255*((gradx-minval)/(maxval-minval)))
5gradx=gradx.astype("uint8")
6#执行gradX?图像的Otsu和二进制阈值,然后是另一个关闭操作,对数字分段
7gradx=cv2.morphologyEx(gradx,cv2.MORPH_CLOSE,rectKernel)
?
图5 执行关闭操作图片效果
(5)图像阈值处理,二值化操作
1thresh=cv2.threshold(gradx,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]

图6 执行二值化操作图片效果
(6)执行膨胀操作,扩大噪音或者连接物体
1kernel=np.ones((7,7),np.uint8)
2dilate=cv2.dilate(thresh,kernel,iterations=1)
?
图7 执行膨胀操作图片效果
(7)找到轮廓并初始化数字分组位置列表。然后循环遍历轮廓,同时根据每个的宽高比进行过滤,允许我们从信用卡的其他不相关区域修剪数字组位置,其中我们需要提取的区域长宽比是大于1,去除杂项。然后从左到右对分组进行排序,并初始化信用卡数字列表。接着利用for循环依次显示和识别。其中文字识别使用的是百度接口。
1#找到轮廓并初始化数字分组位置列表
2cnts=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
3cnts=imutils.grab_contours(cnts)
4locs?=?[]
5#循环遍历轮廓,同时根据每个的宽高比进行过滤,允许我们从信用卡的其他不相关区域修剪数字组位置
6for?(i,?c)?in?enumerate(cnts):
7????(x,?y,?w,?h)?=?cv2.boundingRect(c)
8????#我们需要提取的区域长宽比是大于1,去除杂项
9????ar?=?w/h
10????if?ar?>?1:
11????????locs.append((x,?y,?w,?h))
12#从左到右对分组进行排序,并初始化信用卡数字列表
13locs?=?sorted(locs,?key=lambda?x:x[0])
14print(locs)
15for?i?in?locs:
16????print(i)
17????image=gray[i[1]:i[1]+i[3],i[0]:i[0]+i[2]]
18????cv2.imwrite("temp.jpg",image)
19????APP_ID?=?'23109663'??#?刚才获取的?ID,下同
20????API_KEY?=?'4rWRc7ensuq0Bf8NGs8cGuaz'
21????SECRECT_KEY?=?'bWWS8ugAs2wGGx78yTUiMccpQpWt0UlY'
22????client?=?AipOcr(APP_ID,?API_KEY,?SECRECT_KEY)
23????tt?=?open("temp.jpg",?'rb')
24????img?=?tt.read()
25????message?=?client.basicGeneral(img)??#通用文字识别
26????print(message)
27????cv2.imshow(str(i)+"2",image)
28????cv2.waitKey(1)
29cv2.waitKey(0)
?
图8 识别提取效果图

总结与讨论

此次校园卡目标检测和图像处理信息提取的功能设计,使用的是传统的模式识别方法进行图像识别,其中涉及到的知识主要是hog特征+SVM分类,以及图片处理的一些常规操作和百度API文字识别的调用。
作者简介:李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等。
更多精彩推荐

?一口一个,超灵活的Python迷你项目

?疫情期间网络攻击花样翻新,全年 81748 起安全事件背后暗藏规律

?用数据分析《你好,李焕英》“斐妈”爆红的真相

?最低售价17999元,华为发布新一代折叠屏手机Mate X2

点分享
点收藏
点点赞
点在看

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接