使用Python+OpenCV进行卡类型及16位卡号数字的OCR功能

目录
  • 1. 效果图
  • 2. 原理
    • 2.1 OCR-A字体
    • 2.2 检测过程步骤
    • 2.3 优化
  • 3. 源代码

这篇博客将介绍如何通过OpenCV和Python使用模板匹配执行光学字符识别(OCR)。具体来说,将使用Python+OpenCV实现模板匹配算法,以自动识别卡的类型和以及16位卡号数字。

在比较数字时,模板匹配是一种非常快速的方法。

为此将图像处理管道分为4个步骤:

  1. 通过各种图像处理技术检测信用卡上四组四个数字,包括形态学操作、阈值和轮廓提取。
  2. 从四个分组中提取每个单独的数字,得到16个需要分类的数字。
  3. 将模板匹配应用于每个数字,将其与OCR-A字体进行比较,以获得数字分类。
  4. 检查信用卡号的第一位数字以确定发卡公司。

在对信用卡OCR系统进行评估后,发现如果发卡信用卡公司使用OCR-A字体作为数字,该系统的准确率为100%。 优化可以考虑在野外采集信用卡的真实图像,并训练机器学习模型(通过标准特征提取或训练或卷积神经网络),以进一步提高此系统的准确性。

1. 效果图

首先了解一下卡的组成:

OCR-A 参考字体识别如下:原始图 VS 灰度图 VS 阈值化图 VS 轮廓每个数字提取图:
灰度图:忽略颜色对轮廓提取的影响
阈值化图:使得轮廓在前景白色,背景黑色便于轮廓提取。
轮廓提取图:提取每个数字ROI并记录,方便后续对比卡片中的区域以识别出对应的数字。

以下卡号均是演示卡,
正确的识别卡的类型和卡号,效果图1:

识别过程1——原图 VS 灰度图 VS 白帽图 VS 梯度图如下:
灰度图:忽略色彩影响
白帽图:从较暗的背景中提取较亮的区域
梯度图:计算Schaar梯度图,便于了解图像的色彩分配及提取;

识别过程2——形态学闭合图 VS 二值化图1 VS 阈值化图2 如下:
形态学闭合图:矩形框形态学闭合操作,以帮助闭合信用卡数字之间的小的缝隙
二值化图:以便于提取
阈值化图:方形框形态学闭合操作,以二次帮助闭合信用卡数字区域之间的缝隙

识别过程3——轮廓过滤图 VS 提取最终效果图 如下:
轮廓过滤图:根据面积及纵横比,只保留卡片中的卡号区
最终效果图:提取4组4数字每一个组,然后对每一个组中的4个数字进行截取ROI并识别,并与之前存储的数字ROI进行模板匹配,选取匹配值最高的作为最终结果。

2. 原理

2.1 OCR-A字体

OCR-A字体,是一种专门用于辅助光学字符识别算法的字体。

主要分为:

检测图像中信用卡的位置;本地化信用卡上的四组四位数字;应用OCR识别信用卡上的16位数字;识别信用卡的类型。

Tesseract库在某些情况无法正确识别数字(这可能是因为Tesseract未接受信用卡示例字体培训)。

2.2 检测过程步骤

在字典中存储卡类型映射关系(卡号的第一位数字代表卡类型)。获取参考图像并提取数字。将数字模板存储在字典中。本地化四个信用卡号组,每个组有四位数字(总共16位)。提取要“匹配”的数字。对每个数字执行模板匹配,将每个单独的ROI与每个数字模板0-9进行比较,同时存储每个尝试匹配的分数。查找每个候选数字的最高分数,并构建一个名为“输出”的列表。其中包含信用卡号。将信用卡号和信用卡类型输出到终端,并将输出图像显示到屏幕上。

2.3 优化

使用OpenCV和Python匹配OCR脚本的模板在100%的时间内正确识别了16位数字中的每一位。然而在将OCR图像应用于真实的信用卡图像时,考虑到照明条件、视角和其他一般噪音的变化,可能需要采取更面向机器学习的方法。

3. 源代码

# 信用卡类型及卡号OCR系统
# USAGE
# python ocr_template_match.py --reference images/ocr_a_reference.png --image images/credit_card_05.png

import argparse

import cv2
import imutils
import numpy as np
# 导入必要的包
from imutils import contours

# 构建命令行参数及解析
# --image 必须 要进行OCR的输入图像
# --reference 必须 参考OCR-A图像
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
                help="path to input image")
ap.add_argument("-r", "--reference", required=True,
                help="path to reference OCR-A image")
args = vars(ap.parse_args())

# 定义一个字典(映射信用卡第一位数字和信用卡类型的编号)
FIRST_NUMBER = {
    "3": "American Express",
    "4": "Visa",
    "5": "MasterCard",
    "6": "Discover Card"
}

# 从磁盘加载参考OCR-A图像,转换为灰度图,阈值化图像以显示为白色前景和黑色背景
# 并反转图像
# and invert it, such that the digits appear as *white* on a *black*
ref_origin = cv2.imread(args["reference"])
cv2.imshow("ref_origin", ref_origin)
ref = ref_origin.copy()
ref = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
cv2.imshow("ref_gray", ref)
ref = cv2.threshold(ref, 180, 255, cv2.THRESH_BINARY)[1]
cv2.imshow("ref_threshhold", ref)
cv2.waitKey(0)

# 寻找OCR-A图像中的轮廓(数字的外轮廓线)
# 并从左到右排序轮廓,初始化一个字典来存储数字ROI
refCnts = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,
                           cv2.CHAIN_APPROX_SIMPLE)
print('findContours: ', len(refCnts))
refCnts = imutils.grab_contours(refCnts)
refCnts = contours.sort_contours(refCnts, method="left-to-right")[0]
digits = {}

# 遍历OCR-A轮廓
for (i, c) in enumerate(refCnts):
    # 计算数字的边界框,提取它,缩放到固定的大小
    (x, y, w, h) = cv2.boundingRect(c)
    cv2.rectangle(ref_origin, (x, y), (x + w, y + h), (0, 255, 0), 2)
    roi = ref[y:y + h, x:x + w]
    roi = cv2.resize(roi, (57, 88))

    # 更新数字字典,数字匹配ROI
    digits[i] = roi
cv2.imshow("ref and digits", ref_origin)
cv2.waitKey(0)

# 初始化矩形和方形结构内核
# 在图像上滑动它来进行(卷积)操作,如模糊、锐化、边缘检测或其他图像处理操作。
# 使用矩形函数作为Top-hat形态学运算符,使用方形函数作为闭合运算。
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 准备进行OCR的输入图像
# 加载输入图像,保持纵横比缩放图像宽度为300,转换为灰度图
origin = cv2.imread(args["image"])
origin = imutils.resize(origin, width=300)
image = origin.copy()
cv2.imshow("origin", origin)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)

# 执行形态学操作
# 应用tophat(白帽)形态学操作以在暗的背景中提取出亮的区域(信用卡上的数字卡号)
# Top hat操作在深色背景(即信用卡号)下显示浅色区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv2.imshow("tophat", tophat)

# 计算Scharr梯度,计算梯度值
# 在白色礼帽上,计算x方向的Scharr梯度,然后缩放到范围[0, 255]
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
# 最小/最大归一化, 由float转换gradX到uint8范围[0-255]
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")
cv2.imshow("gradient", gradX)

# 使用矩形框应用闭合操作以帮助闭合信用卡数字之间的小的缝隙
# 应用Otsu's阈值方法二值化图像
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv2.imshow("morphologyEx", gradX)
thresh = cv2.threshold(gradX, 0, 255,
                       cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("thresh1", thresh)

# 在二值化图像上,应用二次闭合操作
# 再一次方形框形态学操作,帮助闭合信用卡数字区域之间的缝隙
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cv2.imshow("thresh2", thresh)

# 阈值图像中查找轮廓,然后初始化数字位置列表
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                        cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
locs = []

# 遍历轮廓
for (i, c) in enumerate(cnts):
    # 计算轮廓的边界框,并计算纵横比
    (x, y, w, h) = cv2.boundingRect(c)
    ar = w / float(h)

    # 由于信用卡有固定的4组4数字,可以根据纵横比来寻找潜在的轮廓
    if ar > 2.5 and ar < 4.0:
        # 轮廓可以在最小/最大宽度上进一步修剪
        if (w > 40 and w < 55) and (h > 10 and h < 20):
            # 添加数字组轮廓的编辑框轮廓到位置list
            locs.append((x, y, w, h))
            cv2.rectangle(origin, (x, y), (x + w, y + h), (255, 0, 0), -1)

cv2.imshow("contours filter", origin)
# 突出显示信用卡上四组四位数字(总共十六位)。
# 从左到右排序轮廓,并初始化list来存储信用卡数字列表
locs = sorted(locs, key=lambda x: x[0])
output = []

# 遍历四组四位数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
    # 初始化存放每组数字的list
    groupOutput = []

    # 提取每组4位数字的灰度图ROI
    # 应用阈值方法从背景信用卡中分割数字
    group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
    group = cv2.threshold(group, 0, 255,
                          cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

    # 检测组中每个单独数字的轮廓
    # 从左到右排序轮廓
    digitCnts = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,
                                 cv2.CHAIN_APPROX_SIMPLE)
    digitCnts = imutils.grab_contours(digitCnts)
    digitCnts = contours.sort_contours(digitCnts,
                                       method="left-to-right")[0]

    # 遍历数字轮廓
    for c in digitCnts:
        # 计算每个单独数字的边界框
        # 提取数字,缩放以拥有和参考OCR-A字体模板图像相同的大小
        (x, y, w, h) = cv2.boundingRect(c)
        roi = group[y:y + h, x:x + w]
        roi = cv2.resize(roi, (57, 88))

        # 初始化模板匹配分数list
        scores = []

        # 遍历参考数字名和数字ROI
        for (digit, digitROI) in digits.items():
            # 应用基于相关性的模板匹配,计算分数,更新分数list
            # apply correlation-based template matching, take the
            # score, and update the scores list
            result = cv2.matchTemplate(roi, digitROI,
                                       cv2.TM_CCOEFF)
            (_, score, _, _) = cv2.minMaxLoc(result)
            scores.append(score)

        # 数字ROI的分类将取 模板匹配分数中分数最大的参考数字
        # the classification for the digit ROI will be the reference
        # digit name with the *largest* template matching score
        groupOutput.append(str(np.argmax(scores)))

    # 围绕每组画一个矩形,并以红色文本标识图像上的信用卡号
    # 绘制每组的数字识别分类结果
    cv2.rectangle(image, (gX - 5, gY - 5),
                  (gX + gW + 5, gY + gH + 5), (0, 0, 255), 2)
    cv2.putText(image, "".join(groupOutput), (gX, gY - 15),
                cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

    # 更新输出数字分组列表
    # Pythonic的方法是使用extend函数,它将iterable对象的每个元素(本例中为列表)追加到列表的末尾
    output.extend(groupOutput)

# 显示检测到的信用卡类型和卡号到屏幕上
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

参考 https://www.pyimagesearch.com/2017/07/17/credit-card-ocr-with-opencv-and-python/

到此这篇关于使用Pyhton+OpenCV进行卡类型及16位卡号数字的OCR功能的文章就介绍到这了,更多相关Pyhton+OpenCV卡号数字识别内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Python OpenCV数字识别案例

    前言 实践是检验真理的唯一标准. 因为觉得一板一眼地学习OpenCV太过枯燥,于是在网上找了一个以项目为导向的教程学习.话不多说,动手做起来. 一.案例介绍 提供信用卡上的数字模板: 要求:识别出信用卡上的数字,并将其直接打印在原图片上.虽然看起来很蠢,但既然可以将数字打印在图片上,说明已经成功识别数字,因此也可以将其转换为数字文本保存.车牌号识别等项目的思路与此案例类似. 示例: 原图 处理后的图 二.步骤 大致分为如下几个步骤: 1.模板读入 2.模板预处理,将模板数字分开,并排序 3.输入

  • Python+Opencv实现数字识别的示例代码

    一.什么是数字识别?   所谓的数字识别,就是使用算法自动识别出图片中的数字.具体的效果如下图所示: 上图展示了算法的处理效果,算法能够自动的识别到LCD屏幕上面的数字,这在现实场景中具有很大的实际应用价值.下面我们将对它的实现细节进行详细解析. 二.如何实现数字识别?   对于数字识别这个任务而言,它并不是一个新的研究方向,很久之前就有很多的学者们在关注这个问题,并提出了一些可行的解决方案,本小节我们将对这些方案进行简单的总结. 方案一:使用现成的OCR技术. OCR,即文字识别,它是一个比较

  • python opencv实现信用卡的数字识别

    本项目利用python以及opencv实现信用卡的数字识别 前期准备 导入工具包 定义功能函数 模板图像处理 读取模板图像 cv2.imread(img) 灰度化处理 cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 二值化 cv2.threshold() 轮廓 - 轮廓 信用卡图像处理 读取信用卡图像 cv2.imread(img) 灰度化处理 cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 礼帽处理 cv2.morphologyEx(gray

  • python基于OpenCV模板匹配识别图片中的数字

    前言 本博客主要实现利用OpenCV的模板匹配识别图像中的数字,然后把识别出来的数字输出到txt文件中,如果识别失败则输出"读取失败". 操作环境: OpenCV - 4.1.0 Python 3.8.1 程序目标 单个数字模板:(这些单个模板是我自己直接从图片上截取下来的) 要处理的图片: 终端输出: 文本输出: 思路讲解 代码讲解 首先定义两个会用到的函数 第一个是显示图片的函数,这样的话在显示图片的时候就比较方便了 def cv_show(name, img): cv2.imsh

  • 使用Python+OpenCV进行卡类型及16位卡号数字的OCR功能

    目录 1. 效果图 2. 原理 2.1 OCR-A字体 2.2 检测过程步骤 2.3 优化 3. 源代码 这篇博客将介绍如何通过OpenCV和Python使用模板匹配执行光学字符识别(OCR).具体来说,将使用Python+OpenCV实现模板匹配算法,以自动识别卡的类型和以及16位卡号数字. 在比较数字时,模板匹配是一种非常快速的方法. 为此将图像处理管道分为4个步骤: 通过各种图像处理技术检测信用卡上四组四个数字,包括形态学操作.阈值和轮廓提取. 从四个分组中提取每个单独的数字,得到16个需

  • Python OpenCV实现识别信用卡号教程详解

    目录 通过与 OpenCV 模板匹配的 OCR 信用卡 OCR 结果 总结 今天的博文分为三个部分. 在第一部分中,我们将讨论 OCR-A 字体,这是一种专为辅助光学字符识别算法而创建的字体. 然后我们将设计一种计算机视觉和图像处理算法,它可以: 本地化信用卡上的四组四位数字. 提取这四个分组中的每一个,然后单独分割 16 个数字中的每一个. 使用模板匹配和 OCR-A 字体识别 16 个信用卡数字中的每一个. 最后,我们将看一些将信用卡 OCR 算法应用于实际图像的示例. 通过与 OpenCV

  • python OpenCV实现答题卡识别判卷

    本文实例为大家分享了python OpenCV实现答题卡识别判卷的具体代码,供大家参考,具体内容如下 完整代码: #导入工具包 import numpy as np import argparse import imutils import cv2 # 设置参数 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", default="./images/test_03.png"

  • Python+Opencv答题卡识别用例详解

    使用Python3和Opencv识别一张标准的答题卡.大致的过程如下: 1.读取图片 2.利用霍夫圆检测,检测出四个角的黑圆位置,从确定四个角的位置 3.利用透视变换和四个角的位置,矫正图片(直接用的网上的图片,没有拍照,所以这一步没有实现) 4.裁剪四个边框,获取边框上小黑格的位置 5.根据小黑格的位置确定每个涂卡区域的位置 6.将答题卡腐蚀和膨胀,遍历所有的格子的区域,计算每个区域内像素值为0的个数,若数量达到某个值,那么就确认这个格子是被黑笔涂过,并记录该位置的题目选项. 具体的实现 一.

  • Python Opencv中用compareHist函数进行直方图比较对比图片

    图像直方图 图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的.纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比. 图像是由像素构成,因为反映像素分布的直方图往往可以作为图像一个很重要的特征.在实际工程中,图像直方图在特征提取.图像匹配等方面都有很好的应用. 直方图比较 1. 图像相似度比较 如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的

  • Python OpenCV招商银行信用卡卡号识别的方法

    学在前面 从本篇博客起,我们将实际完成几个小案例,第一个就是银行卡号识别,预计本案例将写 5 篇左右的博客才可以完成,一起加油吧. 本文的目标是最终获取一套招商银行卡,0~9 数字的图,对于下图的数字,我们需要提取出来,便于后续模板匹配使用.不过下图中找到的数字不完整,需要找到尽量多的卡片,然后补齐这些数字. 提取卡片相关数字 先对上文中卡片中的数字进行相关提取操作,加载图片的灰度图,获取目标区域.在画板中模拟一下坐标区域,为了便于进行后续的操作. 具体代码如下: import cv2 as c

  • Python opencv医学处理的实现过程

    题目描述 利用opencv或其他工具编写程序实现医学处理. 实现过程 # -*- coding: utf-8 -*- ''' 作者 : 丁毅 开发时间 : 2021/5/9 16:30 ''' import cv2 import numpy as np # 图像细化 def VThin(image, array): rows, cols = image.shape NEXT = 1 for i in range(rows): for j in range(cols): if NEXT == 0:

  • Python OpenCV 图像平移的实现示例

    每次学习新东西的时候,橡皮擦都是去海量检索,然后找到适合自己理解的部分. 再将其拼凑成一个小的系统,争取对该内容有初步理解. 今天这 1 个小时,核心要学习的是图像的平移,在电脑上随便打开一张图片,实现移动都非常简单,但是在代码中,出现了一些新的概念. 检索 OpenCV 图像平移相关资料时,碰到的第一个新概念是就是 仿射变换. 每次看到这样子的数学名字,必然心中一凉,做为一个数学小白,又要瑟瑟发抖了. 百度一下,看看百科中是如何介绍的. 看过上图中的一些相关简介之后,对于这个概念也并没有太深刻

  • 树莓派上利用python+opencv+dlib实现嘴唇检测的实现

    目录 1.安装相关库文件 2.代码部分 3.实验效果 树莓派上利用python+opencv+dlib实现嘴唇检测 项目的目标是在树莓派上运行python代码以实现嘴唇检测,本来以为树莓派的硬件是可以流畅运行实时检测的,但是实验的效果表明树莓派实时检测是不可行,后面还需要改进. 实验的效果如下: 1.安装相关库文件 这里需要用的库有opencv,numpy,dlib. 1.1 安装opencv pip3 install opencv-python 1.2 安装numpy 树莓派中自带了numpy

  • Python OpenCV形态学运算示例详解

    目录 1. 腐蚀 & 膨胀 1.1什么是腐蚀&膨胀 1.2 腐蚀方法 cv2.erode() 1.3 膨胀方法 cv2.dilate() 2. 开运算 & 闭运算 2.1 简述 2.2 开运算 2.3 闭运算 3. morphologyEx()方法 3.1 morphologyEx()方法 介绍 3.2 梯度运算 3.3 顶帽运算 3.4 黑帽运算 1. 腐蚀 & 膨胀 1.1什么是腐蚀&膨胀 腐蚀&膨胀是图像形态学中的两种核心操作 腐蚀可以描述为是让图像沿

随机推荐