openCV--信用卡数字识别

使用openCV做信用卡数字识别

最近学习openCV,在网上找了个小项目,信用卡数字识别,这里做一下笔记,识别信用卡数字的一般处理流程为如下

处理模板

  1. 读取模板:读取模板图片,包含标准的数字图片,使用到cv2.imread
  2. 灰度处理:将彩色图片处理为灰度值,因为默认读入的图片为彩色图片,处理起来比较麻烦,所以我们需要把图片转换为二维的灰度图片使用到cv2.cvtColor(https://blog.csdn.net/xf8964/article/details/100187031)
  3. 二值处理:将灰度图片转换为像素只有0和255的值的图片,使用到的函数cv2.threshold
  4. 查找轮廓:在二值图片上查找图像的轮廓,这是为了方便获取图片的方框图
  5. 显示轮廓:将上面查找到的轮廓显示在原图片上,可以直观的看到效果
  6. 轮廓排序:因为我们的模板图片是从数字0到数字9依次排序的,所以,我们需要将得到的轮廓按照x坐标排序排序,其思路就是根据轮廓图找到方框图,根据方框图的x坐标来从左到右排序图片
  7. 得到数字和其图片数组的字典:我们得到排序的轮廓后,使用轮廓的位置信息在原图中取得图片的数组信息,这样我们就得到了一个字典,字典的key是数字,value是图片的数组,用于比较

输入图片处理

  1. 定义卷积核:其实就是定义一个矩阵,来对图片进行卷积运算cv2.getStructuringElement
  2. 读取图片
  3. 调整大小
  4. 灰度处理
  5. 突出明亮区域,对图片处理,突出轮廓
# 显示图片函数
def cv_show(name, img):
    """"
    use opencv show a image (picture)
    """
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyWindow(name)
def get_template(path, debug=True):
    """
    处理模板图片,获得单个数字图片的字典
    :param path: the path of template
    :param debug: 是否显示识别过程中的中间图片,默认显示
    :return: a dictionary, key is index number, value is image
    """
    # open image
    img = cv2.imread(path)
    print(type(img))
    print(img.shape)
    if debug:
        cv_show("img", img)
    # 灰度处理
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    if debug:
        cv_show("gray", gray)
    # 二值处理
    ret, binary = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY_INV)
    if debug:
        cv_show("binary", binary)
    # 查找轮廓
    ref_, contours, hierarchy = cv2.findContours(binary.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 显示轮廓
    cv2.drawContours(img, contours, -1, (0, 0, 255), 3)
    if debug:
        cv_show("img", img)
    # 轮廓排序
    # print(binary.shape)
    template = {}
    contours = utils.sort_contours(contours, method="left-to-right")[0]
    for (i, c) in enumerate(contours):
        (x, y, w, h) = cv2.boundingRect(c)
        roi = binary[y:y + h, x:x + w]
        roi = cv2.resize(roi, (57, 88))
        template[i] = roi
    # 返回轮廓字典
    if debug:
        for i in range(len(template)):
            cv_show("template", template[i])
    return template
def process_input_picture(path, debug=True):
    # 定义卷积核 返回一个矩阵MORPH_RECT为矩形
    rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
    sq_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
    # 读入图片
    image = cv2.imread(path)
    if debug:
        cv_show("input", image)
    # 调整大小
    image = utils.resize(image, width=300)
    # 灰度处理
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    if debug:
        cv_show("gray", gray)
    # 突出明亮区域
    tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rect_kernel)
    if debug:
        cv_show("tophat", tophat)
    gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=3)
    gradX = cv2.convertScaleAbs(gradX)
    if debug:
        cv_show("gradX", gradX)
    gradY = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=3)
    gradY = cv2.convertScaleAbs(gradY)
    if debug:
        cv_show("gradY", gradY)
    gradXY = cv2.addWeighted(gradX, 0.5, gradY, 0.5, 0)
    if debug:
        cv_show("gradXY", gradXY)
    # # 闭:先膨胀,再腐蚀,将突出方块,我想这是为了方便二值处理
    gradXY = cv2.morphologyEx(gradXY, cv2.MORPH_CLOSE, rect_kernel)
    if debug:
        cv_show("gradXY", gradXY)
    # 二值处理,找到方框
    thresh = cv2.threshold(gradXY, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    if debug:
        cv_show('thresh', thresh)
    # 再一次闭操作
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sq_kernel)
    if debug:
        cv_show("thresh", thresh)
    # 查找组合数字的轮廓
    thresh_, thresh_contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cur_img = image.copy()
    cv2.drawContours(cur_img, thresh_contours, -1, (0, 0, 255), 2)
    if debug:
        cv_show("img", cur_img)
    digits = []
    # 获取组合数字快
    for (i, c) in enumerate(thresh_contours):
        # 计算矩形
        (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):
                # 保留
                digits.append((x, y, w, h))
    digits = sorted(digits, key=lambda x: x[0])

    output = []
    for (i, (x, y, w, h)) in enumerate(digits):
        group_output = []
        # 根据坐标提取每一组,也就是一个快
        group = gray[y-5:y+h+5, x-5:x+w+5]
        if debug:
            cv_show("group", group)
        # 二值处理
        group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
        if debug:
            cv_show("group", group)
        group_, digit_contours, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        digit_contours = contours.sort_contours(digit_contours, method="left-to-right")[0]

        for c in digit_contours:
            (x1, y1, w1, h1) = cv2.boundingRect(c)
            roi = group[y1:y1 + h1, x1:x1 + w1]
            roi = cv2.resize(roi, (57,88))
            scores = []

            #匹配模板中每一个数字
            for (digit, digit_roi) in template.items():
                result = cv2.matchTemplate(roi, digit_roi, cv2.TM_CCOEFF)
                #print(result)
                (_, score, _, _) = cv2.minMaxLoc(result)
                #print(score)
                scores.append(score)

            #print(scores)
            group_output.append(str(np.argmax(scores)))
        print(group_output)
        cv2.rectangle(image, (x-5,y-5), (x+w+5,y+h+5), (0,0,255),1)
        # 像图片中输入文字
        cv2.putText(image,"".join(group_output),( x, y-15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0,0,255), 2)
        output.extend(group_output)
    cv2.imshow("Image", image)
    cv2.waitKey(0)

    return digits

调用关系

if __name__ == '__main__':
    print("hello word")

    # 解析模板,返回模板的数字和图片快的字典
    template = get_template(TEMPLATE_PATH, debug=False)
    print("digits len is ", len(template))
    digits = process_input_picture(CREDIT_CARD_PATH, debug=False)
    print("digits len is ", len(digits))
    # 处理预测图片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值