OpenCV信用卡识别代码

PyCharm环境配置

        添加将所需的两个图片的路径

PyCharm中添加OpenCV库

正式代码:

1.导入工具包

from imutils import contours
import numpy as np
import argparse
import cv2
import myutils

2.设置图片的路径

# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", default='./images/credit_card_01.png', help="path to input image")
ap.add_argument("-t", "--template", default='./ocr_a_reference.png', help="path to template OCR image")
args = vars(ap.parse_args())
# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express", "4": "Visa", "5": "MasterCard", "6": "Discover Card"}

argparse.ArgumentParser()函数: argparse模块可以让人轻松编写用户友好的命令行接口

        argparse.ArgumentParser()用法解析_quantLearner的博客-CSDN博客_argparse.argumentparser

3.设置一个显示函数,方便以后的调用

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(500)
    cv2.destroyAllWindows()

4.将图像读进来,然后进行灰度处理和二值化处理

# 读取一个模板图像
img = cv2.imread(args["template"])
cv_show('template', img)
template = cv2.imread(args["image"])
cv_show('image', template)
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('template_gray', ref)
# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('template_bi', ref)

cv2.cvtColor()函数

cv2.cvtColor(p1,p2) 是颜色空间转换函数,p1是需要转换的图片,p2是转换成何种格式。

cv2.imread()和cv2.cvtColor() 的使用_静茹秋叶的博客-CSDN博客_cv2.color_bgr2gray

cv2.threshold()简单阀值函数

CV2简单阈值函数:cv2.threshold()_风华明远的博客-CSDN博客_cv2 threshold

5.计算轮廓,然后遍历每一个轮廓,外接矩形,扣出模板,列出每一个数字对应的模板

# 计算轮廓
# cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
# 返回的list中每个元素都是图像中的一个轮廓
refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  # cv版本大于3.8的,只有两个返回值

cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)  # 轮廓在二值图上得到, 画要画在原图上
cv_show('template_Contours', img)
print(np.array(refCnts).shape)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]  # 排序,从左到右,从上到下
digits = {}  # 存模板的单个数字
# 遍历每一个轮廓,外接矩形
for (i, c) in enumerate(refCnts):  # c是每个轮廓的终点坐标
    # 计算外接矩形并且resize成合适大小
    (x, y, w, h) = cv2.boundingRect(c)
    # 抠出模板
    roi = ref[y:y + h, x:x + w]  # 每个roi对应一个数字
    roi = cv2.resize(roi, (57, 88))  # 太小,调大点

    #  每一个数字对应每一个模板
    digits[i] = roi

cv2.findContours()函数

cv2.drawContours()函数

opencv:图像轮廓检测 cv2.findContours() 与 cv2.drawContours()_宁静致远*的博客-CSDN博客_cv2.findcontours

cv2.boundingRect()函数:矩形边框

该段代码中还涉及一个排序函数(myutils),该函数创建在另一个PythonFile中

myutilsFile函数

# myutils.py
import cv2

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
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized

6.输入图像的处理

#  输入图像处理
#  1.初始化卷积核,根据实际任务指定大小,不一定非要3*3
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
#  2.读取输入图像,预处理
image = cv2.imread(args["image"])
cv_show("Input image", image)
image = myutils.resize(image, width=300)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show("Input_gray", gray)
#  3.礼帽:原始输入-开运算结果(只剩毛刺)
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show("Input tophat", tophat)
#  4.x方向上面的Sobel算子,实验表明只加x效果更好一些
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))
gradx = (255 * ((gradx - minVal) / (maxVal - minVal)))
gradx = gradx.astype("uint8")

print(np.array(gradx).shape)
cv_show("Input_Sobel_gradx", gradx)

#  5.通过闭操作将数字连在一起,将本是4个数字的4个框膨胀成1个框,就腐蚀不掉了
gradx = cv2.morphologyEx(gradx, cv2.MORPH_CLOSE, rectKernel)
cv_show("Input_close_gradx", gradx)

# 6.THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradx, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('Input_thresh', thresh)

# 7.再来一个闭操作
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
cv_show('Input_thresh_CLOSE', thresh)

# 8.计算轮廓
threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                                         cv2.CHAIN_APPROX_SIMPLE)

cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img, cnts, -1, (200, 150, 190), 3)
cv_show('Input_Contours', cur_img)

cv2.morphologyEx()函数

opencv-python 之 cv2.morphologyEx()_一芷泡泡的博客-CSDN博客_morphologyex python

cv2.Sobel()函数

利用cv2.Sobel()计算图像梯度(即边缘检测)的细节讲解_悟影生的博客-CSDN博客

7.遍历轮廓

#  遍历轮廓
# 1.遍历轮廓
locs = []  # 存符合条件的轮廓
for i, c in enumerate(threshCnts):
    # 计算矩形
    x, y, w, h = cv2.boundingRect(c)

    ar = w / float(h)
    # 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
    if 2.5 < ar < 4.0:
        if (40 < w < 55) and (10 < h < 20):
            # 符合的留下来
            locs.append((x, y, w, h))
#   append函数,给列表里面添加元素
# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x: x[0])

# 2.遍历每一个轮廓中的数字
output = []  # 存正确的数字
for (i, (gx, gy, gw, gh)) in enumerate(locs):  # 遍历每一组大轮廓(包含4个数字)
    # initialize the list of group digits
    groupOutput = []

    # 根据坐标提取每一个组(4个值)
    group = gray[gy - 5:gy + gh + 5, gx - 5:gx + gw + 5]  # 往外扩一点
    cv_show('group_' + str(i), group)
    # 2.1 预处理
    group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]  # 二值化的group
    # cv_show('group_'+str(i),group)
    # 计算每一组的轮廓 这样就分成4个小轮廓了
    digitCnts = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
    # 排序
    digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]

    # 2.2 计算并匹配每一组中的每一个数值
    for c in digitCnts:  # c表示每个小轮廓的终点坐标
        z = 0
        # 找到当前数值的轮廓,resize成合适的的大小
        (x, y, w, h) = cv2.boundingRect(c)  # 外接矩形
        roi = group[y:y + h, x:x + w]  # 在原图中取出小轮廓覆盖区域,即数字
        roi = cv2.resize(roi, (57, 88))
        # cv_show("roi_"+str(z),roi)

        # 计算匹配得分: 0得分多少,1得分多少...
        scores = []  # 单次循环中,scores存的是一个数值 匹配 10个模板数值的最大得分

        # 在模板中计算每一个得分
        # digits的digit正好是数值0,1,...,9;digitROI是每个数值的特征表示
        for (digit, digitROI) in digits.items():
            # 进行模板匹配, res是结果矩阵
            res = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)  # 此时roi是X digitROI是0 依次是1,2.. 匹配10次,看模板最高得分多少
            Max_score = cv2.minMaxLoc(res)[1]  # 返回4个,取第二个最大值Maxscore
            scores.append(Max_score)  # 10个最大值
        print("scores:", scores)
        # 得到最合适的数字
        groupOutput.append(str(np.argmax(scores)))  # 返回的是输入列表中最大值的位置
        z = z + 1
    # 2.3 画出来
    cv2.rectangle(image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)  # 左上角,右下角
    # 2.4 putText参数:图片,添加的文字,左上角坐标,字体,字体大小,颜色,字体粗细
    cv2.putText(image, "".join(groupOutput), (gx, gy - 15),
                cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

    # 2.5 得到结果
    output.extend(groupOutput)
    print("groupOutput:", groupOutput)

cv2.matchTemplate()模板匹配函数

cv2.minMaxLoc():函数功能:假设有一个矩阵a,现在需要求这个矩阵的最小值,最大值,并得到最大值,最小值的索引。咋一看感觉很复杂,但使用这个cv2.minMaxLoc()函数就可全部解决。函数返回的四个值就是上述所要得到的。

cv2.matchTemplate模板匹配和cv2.minMaxLoc()函数_zhaojiafu666的博客-CSDN博客_cv2.matchtemplate函数


8.打印结果

# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Output_image", image)
cv2.waitKey(0)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值