小言_互联网的博客

附代码 | OpenCV实现银行卡号识别,字符识别算法你知多少?

541人阅读  评论(0)

作者 | 李秋键

责编 | Carol

头图 | CSDN 付费下载自视觉中国

随着计算机视觉在我们生活中的应用越来越广泛,大量的字符识别和提取应用逐渐变得越来越受欢迎,同时也便利了我们的生活。像我们生活中的凭借身份码取快递、超市扫码支付的机器等等。

字符识别是模式识别的一个重要应用,首先提取待识别字符的特征;然后对提取出来的特征跟字符模板的特征匹配;最后根据准则判定该字符所属的类别。不同的训练方法,不同的特征提取, 不同的匹配规则,就相应的有不同的字符识别方法,基本上很多就是在这些地方做改进,或者是采用新的规则。但是万变不离其宗。

1、模板匹配字符识别算法。

模板匹配字符识别算法是图像识别中的经典算法之一,该算法的核心思想是:通过比较待识别字符图像的字符特征和标准模板的字符特征,计算两者之间的相似性,相似性最大的标准模板的字符即为待识别的字符。

2、神经网络字符识别算法

主要思想:通过神经网络学习大量字符样本,从而得到字符的样本特征。当对待识别的字符进行识别时,神经网络就会将待识别字符的特征和之前得到的样本特征匹配,从而识别出字符。

3、支持向量机

主要思想:同上,都是先得到样本特征,进行训练,然后再分类。SVM应该算是用的最多的分类方法,一般大多适合于二分类问题,在这里就需要使用多分类器来构造。

今天我们就简单的利用OpenCV处理通过提取轮廓和匹配等方式来实现模式匹配的字符识别。

效果图如下:

 

实验前的准备

首先我们使用的python版本是3.6.5所用到的库有cv2库用来图像处理;

Numpy库用来矩阵运算,这里主要用来对图像像素值相关性处理;imutils库可以轻松实现基本图像处理功能,如平移,旋转,调整大小,骨架化和显示Matplotlib图像。

程序的搭建

1、参考图像的读取和处理:

参考图像如下,因为银行卡号主要只有0~9这几个数字,为了方便识别数字,我们直接利用这张图片里的数值作为匹配样式:

所以下面我们要做的事很明显,就是要将其中每个数字隔开方便后面匹配。

代码如下:


   
  1. #定义了一个字典 FIRST_NUMBER  ,它将第一个数字映射到相应的信用卡类型。
  2. FIRST_NUMBER = {
  3.      "3""American Express",
  4.      "4""Visa",
  5.      "5""MasterCard",
  6.      "6""Discover Card"
  7. }
  8. #参考数字图像,用于匹配
  9. #灰度化及二值化
  10. ref=cv2.imread( "1.png")
  11. ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
  12. ref = cv2.threshold(ref,  10255, cv2.THRESH_BINARY_INV)[ 1]
  13. #查找轮廓,从左往右排序
  14. refCnts = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,
  15.     cv2.CHAIN_APPROX_SIMPLE)
  16. refCnts = imutils.grab_contours(refCnts)
  17. refCnts = contours.sort_contours(refCnts, method= "left-to-right")[ 0]
  18. digits = {}
  19. #对于其中每一个轮廓进行提循环,i为数字名称,c为轮廓,我们将每个数字0-9(字典键)与第30行的每个roi   图像(字典值)相关联 。
  20. for (i,c) in enumerate(refCnts):
  21.     (x,y,w,h)=cv2.boundingRect(c)
  22.     roi=ref[y:y+h,x:x+w]
  23.     roi=cv2.resize(roi,( 57, 88))
  24.     digits[i]=roi
  25. #初始化几个结构化内核,构造了两个这样的内核 - 一个矩形和一个正方形。我们将使用矩形的一个用于Top-hat形态运算符,将方形一个用于关闭操作。
  26. rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,( 9, 3))
  27. sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,( 5, 5))

2、获取数字位置分组:

这里需要识别的图片为:

我们需要进行的处理包括二值化和Top-hat形态操作,最后通过findContours函数框出位置。

其中代码如下:


   
  1. #加载信用卡图像
  2. image=cv2.imread( "3.jpg")
  3. image=imutils.resize(image,width= 300)
  4. gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
  5. #执行Top-hat形态操作,将结果存储为 tophat,Top-hat操作显示了深色背景下的亮区(即信用卡号)
  6. tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
  7. #计算沿x方向的渐变在计算gradX   数组中每个元素的绝对值之后 ,我们采取一些步骤将值缩放到范围[0-255](因为图像当前是浮点数据类型)。要做到这一点,我们计算 MINVAL
  8. #   和 MAXVAL   的 gradX   (线72),然后由我们的缩放方程上显示  线73(即,最小/最大归一化)。最后一步是将gradX转换   为 uint8   ,其范围为[0-255]
  9. gradx=cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx= 1,dy= 0,ksize= -1)
  10. gradx=np.absolute(gradx)
  11. (minval,maxval)=(np.min(gradx),np.max(gradx))
  12. gradx=( 255*((gradx-minval)/(maxval-minval)))
  13. gradx=gradx.astype( "uint8")
  14. #执行gradX 图像的Otsu和二进制阈值,然后是另一个关闭操作,对数字分段
  15. gradx=cv2.morphologyEx(gradx,cv2.MORPH_CLOSE,rectKernel)
  16. thresh=cv2.threshold(gradx, 0, 255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[ 1]
  17. thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
  18. #找到轮廓并初始化数字分组位置列表
  19. cnts=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
  20. cnts=imutils.grab_contours(cnts)

3、切割字符:

接着循环遍历轮廓,同时根据每个的宽高比进行过滤,允许我们从信用卡的其他不相关区域修剪数字组位置,然后从左到右对分组进行排序,并初始化信用卡数字列表。

部分代码如下:


   
  1. locs = []
  2. #循环遍历轮廓,同时根据每个的宽高比进行过滤,允许我们从信用卡的其他不相关区域修剪数字组位置
  3. for (i, c) in enumerate(cnts):
  4.      # compute the bounding box of the contour, then use the
  5.      # bounding box coordinates to derive the aspect ratio
  6.     (x, y, w, h) = cv2.boundingRect(c)
  7.     ar = w / float(h)
  8.      # since credit cards used a fixed size fonts with 4 groups
  9.      # of 4 digits, we can prune potential contours based on the
  10.      # aspect ratio
  11.      if ar >  2.5  and ar <  4.0:
  12.          # contours can further be pruned on minimum/maximum width
  13.          # and height
  14.          if (w >  40  and w <  55and (h >  10  and h <  20):
  15.              # append the bounding box region of the digits group
  16.              # to our locations list
  17.             locs.append((x, y, w, h))
  18. #从左到右对分组进行排序,并初始化信用卡数字列表
  19. locs = sorted(locs, key=lambda x:x[ 0])
  20. output = []
  21. #遍历四个排序的分组并确定其中的数字,循环的第一个块中,我们在每一侧提取并填充组5个像素(第125行)
  22. # ,应用阈值处理(第126和127行),并查找和排序轮廓(第129-135行)。
  23. for (i, (gX, gY, gW, gH)) in enumerate(locs):
  24.      # initialize the list of group digits
  25.     groupOutput = []
  26.      # extract the group ROI of 4 digits from the grayscale image,
  27.      # then apply thresholding to segment the digits from the
  28.      # background of the credit card
  29.     group = gray[gY -  5:gY + gH +  5, gX -  5:gX + gW +  5]
  30.     group = cv2.threshold(group,  0255,
  31.         cv2.THRESH_BINARY | cv2.THRESH_OTSU)[ 1]
  32.      # detect the contours of each individual digit in the group,
  33.      # then sort the digit contours from left to right
  34.     digitCnts = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,
  35.         cv2.CHAIN_APPROX_SIMPLE)
  36.     digitCnts = imutils.grab_contours(digitCnts)
  37.     digitCnts = contours.sort_contours(digitCnts,
  38.         method= "left-to-right")[ 0]
  39.      # loop over the digit contours
  40.      for c in digitCnts:
  41.          # compute the bounding box of the individual digit, extract
  42.          # the digit, and resize it to have the same fixed size as
  43.          # the reference OCR-A images
  44.         (x, y, w, h) = cv2.boundingRect(c)
  45.         roi = group[y:y + h, x:x + w]
  46.         roi = cv2.resize(roi, ( 5788))
  47.          # initialize a list of template matching scores
  48.         scores = []
  49.          # loop over the reference digit name and digit ROI
  50.          for (digit, digitROI) in digits.items():
  51.              # apply correlation-based template matching, take the
  52.              # score, and update the scores list
  53.             result = cv2.matchTemplate(roi, digitROI,
  54.                 cv2.TM_CCOEFF)
  55.             (_, score, _, _) = cv2.minMaxLoc(result)
  56.             scores.append(score)
  57.          # the classification for the digit ROI will be the reference
  58.          # digit name with the *largest* template matching score
  59.         groupOutput.append(str(np.argmax(scores)))
  60.      # draw the digit classifications around the group
  61.     cv2.rectangle(image, (gX -  5, gY -  5),
  62.         (gX + gW +  5, gY + gH +  5), ( 00255),  2)
  63.     cv2.putText(image,  "".join(groupOutput), (gX, gY -  15),
  64.         cv2.FONT_HERSHEY_SIMPLEX,  0.65, ( 00255),  2)
  65.      # update the output digits list
  66.     output.extend(groupOutput)
  67. # display the output credit card information to the screen
  68. print( "Credit Card Type: {}".format(FIRST_NUMBER[output[ 0]]))
  69. print( "Credit Card #: {}".format( "".join(output)))
  70. cv2.imshow( "Image", image)
  71. cv2.waitKey( 0)

到这里,我们整体的程序就搭建完成,下面为我们程序的运行结果:

源码地址:

链接:https://pan.baidu.com/s/16t7ZK4j1F6yzp2ynVQol0w

提取码:k5ra

作者简介:

李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等等。

推荐阅读

    你点的每个“在看”,我都认真当成了AI


转载:https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/106416276
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场