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, 10001e-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 papersoft 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=(44), padding=(88), scale=1.05)
9    for (x, y, w, h) in rects:
10        cv2.rectangle(frame, (x, y), (x + w, y + h), (00255), 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/

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