信用卡数字识别

 © Fu Xianjun. All Rights Reserved

 

对模板图片进行处理,得到每个数字的模板
import cv2
import numpy as np
def cv_show(name, img):
   cv2.imshow(name, img)
   cv2.waitKey(0)
   cv2.destroyAllWindows()
def sort_contours(cnts, method="left-to-right"):
   reverse = False
   i = 0
   if method == "right-to-left" or method == "bottom-to-top":
   reverse = True
   if method == "top-to-bottom" or method == "bottom-to-top":
   i = 1
   boundingBoxes = [cv2.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来 
                                                  x,y,h,w
   (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                              key=lambda b: b[1][i], reverse=reverse))
   return cnts, boundingBoxes
# 读取模板图片
template = cv2.imread('ocr_a_reference.png')
cv_show('template', template)
# 模板图片灰度化。这里的模板图片本身就是二值化的因此没有明显区别。
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
cv_show('templage_gray', template_gray)
# 二值化,转化为数字为白色,背景为黑色的图片。
template_binary = cv2.threshold(template_gray, 127, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('template_binary', template_binary)
这里 threshold 后面的 [1] 表示取 threshold 函数返回值的第二个。 threshold 函数返回值为阈值和二值化后的图片,即这里仅保存返回后的图片。
# 根据二值化的模板图,进行轮廓检测
cnts, hierarchy = cv2.findContours(template_binary
                             , cv2.RETR_EXTERNAL
                             , cv2.CHAIN_APPROX_SIMPLE)
# 画出每个数字的轮廓
template_rect = cv2.drawContours(template.copy(), cnts, -1, (0,0,255), 2)
cv_show('template_rect', template_rect)
# 对十个数字根据左上角的位置进行排序,这样数字按照从小到大的顺序排列出来。
cnts = sort_contours(cnts, method="left-to-right")[0]
number = {}
# 根据排列的结果,将每个数字截取出来。将每个数字图片所对应的数字对应起来。
# 这里要注意,对像素值进行取值时,数组的行对应的是图片的y轴,列对应的图片的x轴。
for (i, cnt) in enumerate(cnts):
    (x,y,w,h) = cv2.boundingRect(cnt)
    roi = template_binary[y:y+h, x:x+w]
    roi = cv2.resize(roi, (57,88))
 
    number[i] = roi
对信用卡信息进行处理,去除多余的背景信息。
# 读取信用卡图片
cardImg = cv2.imread('credit_card_02.png')
cardImg = cv2.resize(cardImg
 , (300, int(float(300 / cardImg.shape[1]) * cardImg.shape[0]))
 , interpolation=cv2.INTER_AREA)
cv_show('cardImg', cardImg)
cardImg_gray = cv2.cvtColor(cardImg, cv2.COLOR_BGR2GRAY)
cv_show('cardImg_gray', cardImg_gray)
# 指定卷积核大小
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 进行礼帽操作
cardImg_tophat = cv2.morphologyEx(cardImg_gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('cardImg_open', cardImg_tophat)
对信用卡上的数字进行选取,对于非卡号数字进行剔除。
# 使用sobel算子进行边缘检测,这里仅适用x方向的梯度。因为经过实验,使用x,y混合的梯度,效果并不理想。
sobelx = cv2.Sobel(cardImg_tophat, cv2.CV_64F, 1, 0, ksize=3)
sobelx = cv2.convertScaleAbs(sobelx) (minX, maxX) = (np.min(sobelx), np.max(sobelx))
sobelx = (255 * ((sobelx - minX) / (maxX - minX)))
sobelx = sobelx.astype('uint8')
cv_show('sobelx', sobelx)
#进行闭运算,使相邻的数字连接起来,这样便于筛选。
cardImg_close = cv2.morphologyEx(sobelx, cv2.MORPH_CLOSE, rectKernel)
cv_show('cardImg_close', cardImg_close)
cardImg_binary = cv2.threshold(cardImg_close, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)[1]
cv_show('cardImg_binary', cardImg_binary)
cardImg_close = cv2.morphologyEx(cardImg_binary, cv2.MORPH_CLOSE, sqKernel)
cv_show('cardImg_close', cardImg_close)
# 轮廓检测,检测出每一个数字区块
cnts, hierarchy = cv2.findContours(cardImg_close
 , cv2.RETR_EXTERNAL
 , cv2.CHAIN_APPROX_SIMPLE)
cardImg_cnts = cv2.drawContours(cardImg.copy(), cnts, -1, (0,0,255), 2)
cv_show('cardImg_cnts', cardImg_cnts)
# 对轮廓进行筛选, 根据边框的尺寸仅保留卡号区域
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))
locs = sorted(locs, key=lambda x: x[0])
得到卡号区域后,对卡号进行数字划分。进行模板匹配,得到每个数字图像所对应的数字。
output = []
# 对每个4数字块进行处理
for (i, (x, y, w, h)) in enumerate(locs):
    group_output = []
    group = cardImg_gray[y-5:y + h + 5, x-5:x + w + 5]
    group = cv2.threshold(group, 0, 255, cv2.THRESH_OTSU|cv2.THRESH_BINARY)[1]
    cv_show('group', group)
    group_cnts, group_hierarchy = cv2.findContours(group, cv2.RETR_EXTERNAL
                                                    , cv2.CHAIN_APPROX_SIMPLE)
    group_cnts = sort_contours(group_cnts, method="left-to-right")[0]
 # 分割每个数字
    for cnt in group_cnts:
        (nx,ny,nw,nh) = cv2.boundingRect(cnt)
        roi = group[ny:ny+nh, nx:nx+nw]
        roi = cv2.resize(roi, (57, 88))
        cv_show('roi', roi)
        score = []
 # 对每个数字进行模板匹配
        for (number_i, number_roi) in number.items():
            result = cv2.matchTemplate(roi, number_roi, cv2.TM_CCOEFF)
            score_ = cv2.minMaxLoc(result)[1]
            score.append(score_)
            group_output.append(str(np.argmax(score)))
# 绘制每个数字
    cv2.rectangle(cardImg, (x - 5, y - 5),
                  (x + w + 5, y + h + 5), (0, 0, 255), 1)
    cv2.putText(cardImg, "".join(group_output), (x, y - 15),
    cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
    output.append(group_output)
cv_show('cardImg', cardImg)

出现这个错误的原因是在导入seaborn包时,无法从typing模块中导入名为'Protocol'的对象。 解决这个问题的方法有以下几种: 1. 检查你的Python版本是否符合seaborn包的要求,如果不符合,尝试更新Python版本。 2. 检查你的环境中是否安装了typing_extensions包,如果没有安装,可以使用以下命令安装:pip install typing_extensions。 3. 如果你使用的是Python 3.8版本以下的版本,你可以尝试使用typing_extensions包来代替typing模块来解决该问题。 4. 检查你的代码是否正确导入了seaborn包,并且没有其他导入错误。 5. 如果以上方法都无法解决问题,可以尝试在你的代码中使用其他的可替代包或者更新seaborn包的版本来解决该问题。 总结: 出现ImportError: cannot import name 'Protocol' from 'typing'错误的原因可能是由于Python版本不兼容、缺少typing_extensions包或者导入错误等原因造成的。可以根据具体情况尝试上述方法来解决该问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ImportError: cannot import name ‘Literal‘ from ‘typing‘ (D:\Anaconda\envs\tensorflow\lib\typing....](https://blog.youkuaiyun.com/yuhaix/article/details/124528628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值