社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

CSDN • 4 年前 • 581 次点击  

【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, 10001 e-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竞赛获奖等。

美团优选、多多买菜等五家社区团购被罚650万元;打车手机越贵,接单车型越贵;微软推出低代码语言 Power Fx | 极客头条
你还有学了三年建模的朋友吗?他有救了
亚马逊力推以太坊,微软谷歌准备跟进!
三年白干!程序员孙某因违反《竞业协议》赔偿腾讯 97.6 万元,返还 15.8 万元
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/108458
 
581 次点击