银行卡数字识别

需求

根据数字模板,自动读取银行卡中的银行卡号码。
credit_card_01.png
ocr_a_reference.png

总体流程

流程

  1. 获取数字模板。从数字图片中,读取每个数字的模板
    1. 导入数字模板图片
    2. 对图像进行灰度转换
    3. 对图像进行二值化处理
    4. 提取数字轮廓
    5. 获取数字的矩形外轮廓。
  2. 模板匹配。将数字模板与银行卡图片中的模板进行匹配。
    1. 导入银行卡图片
    2. 对银行卡图片进行灰度转换,重新计算图片宽高减小数据
    3. 通过形态学操作,提取数字组
    4. 对数字组进行拆分,将每个数字与数字模板进行模板匹配,识别数字
    5. 输出银行卡号码

实现

获取数字模板

import cv2
import matplotlib.pyplot as plt

'''获取图像数字模板'''
# 导入数字模板图片
ref = cv2.imread('../images/ocr_a_reference.png')
# 对图像进行灰度转换
ref_gray = cv2.cvtColor(ref,cv2.COLOR_BGR2GRAY)
# 对图像进行二值化处理
_,ref_threshold = cv2.threshold(ref_gray,10,255,cv2.THRESH_BINARY_INV)

plt.subplot(231),plt.imshow(ref),plt.title('ORIGIN')
plt.subplot(232),plt.imshow(ref_gray,'gray'),plt.title('GRAY')
plt.subplot(233),plt.imshow(ref_threshold,'gray'),plt.title('THRESH')
plt.show()

image.png

二值化处理函数
函数原型:retval, dst = cv2.threshold(src, thresh, maxval, type) src:输入图像,需要是灰度图像。
thresh:用于对像素值进行分类的阈值。如果像素值大于或等于阈值,则将其设置为最大值,否则设置为最小值。
maxval:最大值,用于将大于阈值的像素值赋值为的最大值。 type:二值化的类型1。OpenCV提供了以下几种类型:

  • cv2.THRESH_BINARY:如果像素值大于阈值,则将其设置为最大值,否则设置为。
  • cv2.THRESH_BINARY_INV:如果像素值大于阈值,则将其设置为0,否则设置为最大值。
  • cv2.THRESH_TRUNC:如果像素值大于阈值,则将其设置为阈值,否则保持不变。
  • cv2.THRESH_TOZERO:如果像素值小于阈值,则将其设置为0,否则保持不变。
  • cv2.THRESH_TOZERO_INV:如果像素值大于阈值,则将其设置为0,否则保持不变。

返回值: retval:使用的阈值。 dst:已二值化的输出图像。

# 提取数字轮廓,因版本问题findContours有三个参数,一般为两个参数
ref_, ref_contours,hierarchy = cv2.findContours(ref_threshold,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)  
# 绘画数字轮廓
ref_outline = ref.copy()
cv2.drawContours(ref_outline,ref_contours,-1,(0,0,255),3)

cv2.imshow('outline',ref_outline)
cv2.waitKey(0)
cv2.destroyAllWindows()

image.png

边缘提取函数
函数原型:contours, hierarchy = cv2.findContours(image, mode, method) image:输入图像,需要是二值图像。 mode:轮廓检索模式。OpenCV提供了以下几种模式:

  • cv2.RETR_EXTERNAL:只检测外轮廓。
  • cv2.RETR_LIST:检测所有轮廓,但不建立轮廓间的等级关系。
  • cv2.RETR_CCOMP:检测所有轮廓并按从左到右的顺序排列。
  • cv2.RETR_TREE:检测所有轮廓并建立轮廓树。

method:轮廓近似方法。常用的有:

  • cv2.CHAIN_APPROX_NONE:存储所有顶点。
  • cv2.CHAIN_APPROX_SIMPLE:仅存储水平、垂直方向上的顶点。
  • cv2.CHAIN_APPROX_TC89_L1:使用TEH_CHAIN近似算法。

返回值: contours:输出的轮廓集合,每个轮廓由一系列点组成。
hierarchy:输出的轮廓层次结构,用于表示轮廓之间的父子关系。
使用cv2.boundingRect函数提取出矩形的外轮廓。但由于我们需要的是每个数字对应的矩形的矩形轮廓,可以针对矩形的横坐标按从大到小进行排序,则可将轮廓和数字一一对应。

# 计算轮廓外接矩形和排序
ref_boundingRects = []
ref_outline = ref.copy()
for cont in ref_contours:
	# 外接矩形
    ref_boundingRects.append(cv2.boundingRect(cont))
    x, y, w, h = cv2.boundingRect(cont)
    # 在原图上画出预测的矩形
    cv2.rectangle(ref_outline, (x, y), (x+w, y+h), (0, 0, 255), 3)

# 对矩形框按左上角横坐标排序,从小到大依次为123....
ref_boundingRects = sorted(ref_boundingRects,key=lambda boundingRect: boundingRect[0])
# 按照矩形框的顺序,从原图像中提取数字影像
digits = []
for index,cout in enumerate(ref_boundingRects):
    x,y,w,h = cout
    roi = ref_gray[y:y+h,x:x+w]
    roi = cv2.resize(roi,(57,88))
    digits.append(roi)

cv_show('outline',ref_outline)

image.png

提取外接矩形函数
函数原型:x, y, w, h = cv.boundingRect(array) array:输入的二维点集,可以是vector或Mat类型。一般输入已经提取好的轮廓信息。 返回值: x, y:矩阵左上点的坐标。
w, h:矩阵的宽和高。

信用卡图像模糊匹配

我们可以通过形态学操作,单独将银行号码以四个为一组,提取出来,一组银行卡号码会被分为四个部分;然后对每个部分在进行边缘提取,提取出每个数字,对每个数字进行模糊匹配即可得该数字所的值。
image.png
形态学操作

# 对图像进行形态学处理
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
img_close = cv2.morphologyEx(img_thresh,cv2.MORPH_CLOSE,rectKernel)

cv_show('img',img_close)

image.png

形态学操作 函数原型:dst = cv.morphologyEx(src, op, kerne) src:输入图像,图像数据类型必须为CV_8U, CV_16U, CV_16S, CV_32F 或 CV_64F中的一种。
op:形态学处理的类型。OpenCV提供了以下几种类型:

  • cv2.MORPH_ERODE:腐蚀处理。
  • cv2.MORPH_DILATE:膨胀处理。
  • cv2.MORPH_OPEN:开运算处理。
  • cv2.MORPH_CLOSE:闭运算处理。
  • cv2.MORPH_GRADIENT:形态学梯度。
  • cv2.MORPH_TOPHAT:顶帽变换。
  • cv2.MORPH_BLACKHAT:黑帽变换。
  • cv2.MORPH_HITMISS:击中-击不中变换。

kernel:结构元矩阵。 返回值: dst:输出图像,即进行形态学操作后的图像。

函数原型:retval = cv.getStructuringElement(shape, ksize[, anchor])
shape:元素的形状。OpenCV提供了以下几种形状:

  • cv2.MORPH_RECT:矩形元素。
  • cv2.MORPH_CROSS:十字形元素。
  • cv2.MORPH_ELLIPSE:椭圆形元素。

ksize:元素的大小。 anchor:锚点的位置,默认值为Point(-1,-1),表示锚点位于元素的中心。 返回值:
retval:返回指定大小和形状的结构元素(MAT类型)。
识别数字组位置

# 识别数字组位置
# 检测外矩形轮廓
_,img_contours,_ = cv2.findContours(img_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
img_boundingRects = []
img_outline = img_resize.copy()
for cont in img_contours:
    # 筛选符合条件的矩形框,如果长宽比在某个阈值之内,则认为符合条件
    boundingRect = cv2.boundingRect(cont) # x, y, w, h 
    x, y, w, h = boundingRect
    ds = w/float(h)
    if((ds > 3.2)&(ds < 3.6)):
        img_boundingRects.append(boundingRect)
        # 在原图上画出预测的矩形
        cv2.rectangle(img_outline, (x, y), (x+w, y+h), (0, 0, 255), 1)

# 按照左上角坐标排序,按横轴从小到大排序
img_boundingRects = sorted(img_boundingRects,key=lambda boundingRect: boundingRect[0])

# 添加到数字组中
card_digits =[]
for boundingRect in img_boundingRects:
    x, y, w, h = boundingRect
    img_ = img_thresh[y-5:y+h+5,x-5:x+w+5]
    card_digits.append(img_)

cv_show('img_outline',img_outline)
for card_digit in card_digits:
    cv_show('img',card_digit)

image.png
image.pngimage.pngimage.pngimage.png
数字模糊匹配
获得到的数字组是一个二值图像,可以直接数字组进行边缘匹配,获取数字的矩形边缘,切割出数字图片。在此之前,我们已经获取了所有的数字模板,将切割出的数字与每个数字模板进行模糊匹配,取出最合适的匹配结果,就可以的到数字图片所对应的数字。

# 对每个数字进行模糊匹配
card_num = ''
for card_digit in card_digits:
    # cv_show('roi',card_digit)
    card_cont_boundingRects = []
    # 边缘提取,提取数字边缘
    _,card_cont,_ = cv2.findContours(card_digit,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
    # 提取矩形边缘,并排序
    for cont in card_cont:
        card_cont_boundingRects.append(cv2.boundingRect(cont))
    card_cont_boundingRects = sorted(card_cont_boundingRects,
                                     key=lambda boundingRect: boundingRect[0])
    # 根据排序后的矩形边缘,切割出图片中数字部分
    for cont in card_cont_boundingRects:
        x,y,w,h = cont
        roi = card_digit[y:y+h,x:x+w]
        roi = cv2.resize(roi,(57,88))
        #cv_show('roi',roi)
        # 根据切割出的数字部分,可以对数字进行模糊匹配
        result = []
        for index,digit in enumerate(digits):
            res = cv2.matchTemplate(roi,digit,cv2.TM_CCOEFF_NORMED)
            result.append(np.abs(res[0,0]))
        # 根据的到的数据,取绝对值最大的为正确的匹配结果
        num = np.where(result==np.max(result))[0][0]
        card_num += str(num)
    card_num += ' '
print(card_num)

image.png

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值