网站应该怎么做运维,商业网站 技术,建筑网格组织,广州有名的网站建设公司实战1-银行卡号识别
项目来源#xff1a;opencv入门
项目目的#xff1a;识别传入的银行卡照片中的卡号
难点#xff1a;银行卡上会有一些干扰项#xff0c;如何排除这些干扰项#xff0c;并且打印正确的号码是一个问题 最终效果如上图
实现这样的功能需要以下几个步骤…实战1-银行卡号识别
项目来源opencv入门
项目目的识别传入的银行卡照片中的卡号
难点银行卡上会有一些干扰项如何排除这些干扰项并且打印正确的号码是一个问题 最终效果如上图
实现这样的功能需要以下几个步骤
首先必须有与银行卡中卡号数字基本一样的数字模板将模板中的数字提取出来并存储起来0-9将需要检测的银行卡图片中的数字提取出来将银行卡的数字与模板数字一一对比最终找到一个匹配度最高的数字并把数字标注上
整个思路很简单但是难点就在于如何将图片处理得更加容易让计算机识别数字所以整个项目要围绕着图片得的处理来做
第一步-提取数字模板
这是事先准备好的数字模板 接下来要将图片中的数字都找到也就是找到各个数字在整个图片上的像素点坐标(轮廓)
首先得到图片的灰度图再进行二值化处理(这一切都是为了让图片中的数字更易于识别)
# 灰度图
ref cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值图像
ref cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]#超过阈值部分取maxval ( 最大值 )否则取0然后会得到这样的图像
好了现在图片已经很清晰了不需要再进行其它的处理了直接将其提取
那怎么提取呢
可以通过cv2.findContours()找到数字的轮廓 函数 cv2.findContours() 有三个参数,第一个是输入图像,第二个是 轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个 是轮廓,第三个是轮廓的层析结构。轮廓第二个返回值是一个 Python 列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包 含对象边界点(x,y)的坐标。 注意新版本中这个api的返回值有变化
返回两个参数contours和 hierarchycontours就是每个数字的轮廓数组包含边界点的坐标
其中cv2.RETR_EXTERNAL是获取外轮廓
contours, hierarchy cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)接下来可以将轮廓画出来看看
会用到cv2.drawContours()函数 函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供 的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一 个 Python 列表。第三个参数是轮廓的索引在绘制独立轮廓是很有用,当设置 -1时绘制所有轮廓。接下来的参数是轮廓的颜色和厚度等。 cv2.drawContours(img,contours,-1, (0, 0, 255), 3)看下效果 好现在轮廓都找到了并且我们也有了轮廓的坐标这个时候我们应该将每个数字的像素点位置都存起来(并不是将图片分割整个图片仍然没有任何变化)
好现在有一个要注意的点那就是我们在上面得到的contours数组并不是按图片中各个数字从左到右排列的也就是说数组中第一个坐标可能是图片中8的坐标那这个时候我们就必须对数组进行排序排序顺序就是从左到右存
那排序怎么实现呢其实就是根据x坐标从小到大排序就行了
排完序之后contours中0下标存的就是数字0的模板这里很好的利用了数组下标的优点
好的排序完之后我们就可以来存这个数字的模板了
思路是遍历contours数组得到每个模板的坐标以及宽高利用xw就能得到图片的x轴范围yh就能得到y轴的范围把他们存起来就得到一个数字的模板了
digits {}
#遍历每一个轮廓
for (i,c) in enumerate(contours):#计算外接矩形并resize合适的大小(x, y, w, h) cv2.boundingRect(c)# cv2.rectangle(img,(x,y),(x w, y h),(0, 0, 255), 2)roi ref[y:y h, x:x w]# 第二个参数是输出图像的宽高roi cv2.resize(roi, (57, 88))# 每一个数字对应每一个模板digits[i] roi
至此我们项目的第一步就完成了
接下来就是将要检测的图像中的数字提取出来其实整个提取思路都是一样的但是银行卡的图像比我们的模板往往更加复杂所以我们要对图片增加一些处理的步骤
跟着上面的来说我们对复杂图片的处理需要引入卷积核这里我们定义两个卷积核
# 初始化卷积核
rectKernel cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
一个是9x3的矩阵一个是5x5
下面对图像进行处理老规矩取灰度图 然后进行礼帽处理目的是为了突出更明亮的区域
tophat cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)接下来再用 Sobel核子对图片进行卷积,目的的为了得到图像梯度也就是边缘检测
我们现在要做的是把可能为数字的区域都找出来
gradX cv2.Sobel(tophat, ddepthcv2.CV_32F, dx1, dy0, ksize-1)
gradX np.absolute(gradX)
(minVal, maxVal) (np.min(gradX), np.max(gradX))
gradX (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX gradX.astype(uint8)上图看上去更加模糊了但是数字和非数字区域的明亮度变了
好的接下来可以通过闭操作先膨胀再腐蚀将数字连起来(是为了最后找到数字区域因为卡号是4个数字连在一起的我们把4个数字的区域找出来)
变成这样 再来一次阈值操作
thresh cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]变成这样 矩形区域好像白色没有填满再来一次闭操作 ok了现在疑似数字的区域都很明显了吧那下一步就是将这个区域进行排除找到真正为银行卡号的区域其他的区域就不要了
那怎么做呢我们先把他们的轮廓都找出来然后判断这些轮廓的宽度符合银行卡号区域宽的的留下不符合的去掉就可以了 # 计算轮廓
contours_, hierarchy_ cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts contours_
cur_img image.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
cv_show(img, cur_img)
locs []
# 遍历轮廓
for (i, c) in enumerate(cnts):# 计算矩形(x, y, w, h) cv2.boundingRect(c)ar w / float(h)# 选择合适的区域根据实际任务来这里的基本都是四个数字一组if ar 2.5 and ar 4.0:if (w 40 and w 55) and (h 10 and h 20):# 符合的留下来locs.append((x, y, w, h))得到卡号轮廓后同样对其从左至右排序
好了那接下来干嘛呢我们刚刚得到的是四个数字组成的区域的轮廓这个时候我们应该遍历这些区域得到里面的四个数字的轮廓
同样也是个遍历操作
for (i, (gX, gY, gW, gH)) in enumerate(locs):groupOutput []# 根据坐标提取每一个组group gray[gY - 5:gY gH 5, gX - 5:gX gW 5]cv_show(group, group)会得到四个这样的组 然后就获取这个组的轮廓就像第一步骤一样将数字提取出来就可以了
#计算每一组的轮廓digitCnts, hierarchy cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)# 从左到右排序digitCnts myutils.sort_contours(digitCnts, methodleft-to-right)[0]好的接下来就是最重要的第三部操作了将模板与上面得到的数字匹配找到匹配度最高的那个模板数字就是我们要找的数字了 #计算每一组的每一个数值for c in digitCnts:# 找到当前数值的轮廓resize成合适的的大小(x, y, w, h) cv2.boundingRect(c)roi group[y:y h, x:x w]roi cv2.resize(roi, (57, 88))# cv_show(roi, roi)# 计算匹配得分scores []for (digit, digitROI) in digits.items():# 模板匹配result cv2.matchTemplate(roi, digitROI,cv2.TM_CCOEFF)# print(result,result)# 获取匹配度最高的数值(_, score, _, _) cv2.minMaxLoc(result)scores.append(score)print(scores,scores)# 得到最合适的数字groupOutput.append(str(np.argmax(scores)))print(groupOutput,groupOutput)完成上述步骤之后我们的groupOutput就存放了我们识别出来的银行卡号了我们只需要在图片上将卡号绘制出来就可以了 # 画出来cv2.rectangle(image, (gX - 5, gY - 5),(gX gW 5, gY gH 5), (0, 0, 255), 1)cv2.putText(image, .join(groupOutput), (gX, gY - 15),cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 得到结果output.extend(groupOutput)最终效果如下 好了以上就是此小项目的实现过程
总结这是我学cv的第一个小实战项目确实感觉蛮有意思的学之前觉得这个东西很神奇学习之后会发现其实一切都是按照逻辑一步步来的没有那么高大上,继续努力吧