Python 实现校园卡目标检测与文字识别系统
【CSDN 编者按】本项目主要从两方面出发,一是搭建目标检测系统,利用hog+svm的方法,从网络摄像头读取数据,目标检测找出校园卡的位置;二是在找到校园卡位置后,保存下单独校园卡图片,然...
【CSDN 编者按】本项目主要从两方面出发,一是搭建目标检测系统,利用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竞赛获奖等。
☞美团优选、多多买菜等五家社区团购被罚650万元;打车手机越贵,接单车型越贵;微软推出低代码语言 Power Fx | 极客头条
☞你还有学了三年建模的朋友吗?他有救了
☞亚马逊力推以太坊,微软谷歌准备跟进!
☞三年白干!程序员孙某因违反《竞业协议》赔偿腾讯 97.6 万元,返还 15.8 万元
更多推荐