美文网首页
图像处理实战-信用卡数字识别(二)

图像处理实战-信用卡数字识别(二)

作者: YvanYan | 来源:发表于2020-06-19 21:41 被阅读0次

    信用卡数字识别的项目需求是:给定一张信用卡,识别出信用卡上的卡号。

    本文内容为该项目的实战,其中用到相关技术和函数请参考《图像处理实战-信用卡数字识别(一)》。
    完整代码:https://github.com/YvanYan/image_processing.git


    该项目的主要思路是使用模板匹配来进行信用卡数字识别。
    其主要流程为:
    1.对模板图片进行处理,得到每个数字的模板。
    2.对信用卡信息进行处理,去除多余的背景信息。
    3.对信用卡上的数字进行选取,对于非卡号数字进行剔除。
    4.得到卡号区域后,对卡号进行数字划分。
    5.进行模板匹配,得到每个数字图像所对应的数字。

    1.对模板图片进行处理,得到每个数字的模板。

    # 读取模板图片
    template = cv2.imread('images/template.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函数返回值为阈值二值化后的图片,即这里仅保存返回后的图片。

    # 根据二值化的模板图,进行轮廓检测
    template_fCnts, 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 = myutils.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
    

    2.对信用卡信息进行处理,去除多余的背景信息。

    # 读取信用卡图片
    cardImg = cv2.imread('images/credit_card_01.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)
    

    3.对信用卡上的数字进行选取,对于非卡号数字进行剔除。

    # 使用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')
    
    # sobely = cv2.Sobel(cardImg_tophat, cv2.CV_64F, 0, 1, ksize=3)
    # sobely = cv2.convertScaleAbs(sobely)
    # (minY, maxY) = (np.min(sobely), np.max(sobely))
    # sobely = (255 * ((sobely - minY) / (maxY - minY)))
    # # sobely = sobely.astype('uint8')
    #
    # sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
    # sobelxy = sobelxy.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)
    # 轮廓检测,检测出每一个数字区块
    cardImg_, 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])
    

    4.得到卡号区域后,对卡号进行数字划分。
    5.进行模板匹配,得到每个数字图像所对应的数字。

    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_, group_cnts, group_hierarchy = cv2.findContours(group
                                                               , cv2.RETR_EXTERNAL
                                                               , cv2.CHAIN_APPROX_SIMPLE)
        group_cnts = contours.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)
    

    相关文章

      网友评论

          本文标题:图像处理实战-信用卡数字识别(二)

          本文链接:https://www.haomeiwen.com/subject/xkspxktx.html