锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

OpenCV实战项目---信用卡识别

时间:2022-08-18 13:00:00 卡边缘连接器card

给定一张信用卡,最后输出上面的卡号,并在原始图片中圈出卡号的位置。这是一个模板匹配任务,如果我们想让计算机知道数字,我们需要给出一个模板。


这样, 我们只需要在信用卡上找到数字区域,然后将数字区域的数字与模板逐一匹配,看看它是什么数字。 然而,对于信用卡,我们需要找到它的数字区域。对于给定的模板,虽然我们有它的数字区域,但我们必须将它们分成数字来匹配工作。因此,这项任务转换为处理信用卡, 处理模板和模板匹配三个子问题。

一般思路如下:

使用轮廓检测算法,找出每个对象的一般轮廓和外部矩形,即先定位到每个对象。找到对象轮廓后,根据外矩形的长宽比,找到中间的长串数字部分。因为轮廓又长又窄,所以很容易找到。对于这学操作使这一长串数字更加突出,使这一部分更加准确。接下来,对于这部分,再次进行轮廓检测,分成四个小块,对于每个小块进行轮廓检测,可以得到每个具体的数字。对于每个数字,匹配模板(直接有函数可用)就知道了。

下面进行代码展示:

import cv2 import numpy as np  # 读取模板图片 img = cv2.imread("./model.png") img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 反二值处理,常见的二值图像一般前景为白色,背景为黑色 img_gray = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)[1]  # 找到图像的轮廓 # CHAIN_APPROX_NONE保存轮廓上的所有点 # RETR_EXTERNAL=0表示值检测外围轮廓 img_g_con = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] img_g_dst = cv2.drawContours(img.copy(), img_g_con, -1, (0, 0, 255), 2)   # 矩形包围盒画模板图片 lst_1 = [] for con in img_g_con:     #最大矩形     (x, y, w, h) = cv2.boundingRect(con)     #(x,y)起始坐标     lst_1.append(x)  # 按照x坐标对其包围盒进行排序,以获得按顺序排列的0~9模板数字图片, # (因为找到的模板是无序的,每个模板对应的数字可以在排序后确认) (img_g_con, lst_1) = zip(*sorted(zip(img_g_con, lst_1), key=lambda x: x[1], reverse=False))  # 将模板数字图像分 digits = {}  # enumerate() 函数用于将可遍历的数据对象(如列表、元组或字符串)组合成索引序列,同时列出数据和数据下标 # sequence -- 一个序列,迭代器或其他支持迭代对象。 # start -- 下标起始位置值。 for i, con in enumerate(img_g_con):     (x, y, w, h) = cv2.boundingRect(con)     roi = img_gray[y:y   h, x:x   w]     #     (57、88)调整后的模板图像大小,也可以设置为其他尺寸     digits[i] = cv2.resize(roi, (57, 88))  # 到目前为止,已经保存了从0到9的模板图像digits模板图像处理完毕。  img_card = cv2.imread("./Card.png") #灰度化 img_card_gray = cv2.cvtColor(img_card, cv2.COLOR_BGR2GRAY)  # 顶帽操作,原始图像-计算图像,功能:提取噪音,亮区。 kernel = np.ones((5, 5)) tophat = cv2.morphologyEx(img_card_gray, cv2.MORPH_TOPHAT, kernel)  #图像梯度 grady = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=3) # Sobel计算出的像素值类似于float,需要规范到(0~255)并将其格式转换为Uint8 grady = cv2.convertScaleAbs(grady) gradx = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=3) gradx = cv2.convertScaleAbs(gradx)  # 将X梯度与Y梯度融为一体。 # 只有单向梯度才能达到目的 grad = cv2.addWeighted(gradx, 0.5, grady, 0.5, 0)  # 使用Canny边缘检测也可以得到类似的效果 # 接下来进行闭合操作(先腐蚀后膨胀),一是去除一些白色的小噪音,二是将单个数字连接到一个小区域 kernel = np.ones((3, 3)) grad_close = cv2.morphologyEx(grad, cv2.MORPH_CLOSE, kernel, iterations=1)  grad_dst = cv2.threshold(grad_close, 0 , 255, cv2.THRESH_OTSU)[1]  # 注意到第三个区域还没有连通,继续进行闭操作 grad_close = cv2.morphologyEx(grad_dst, cv2.MORPH_CLOSE, kernel, iterations=8)  # 目标区域已完全连接,然后进行轮廓检测,绘制包围盒,然后进行筛选 gradcon = cv2.findContours(grad_close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] dst = cv2.drawContours(img_card.copy(), gradcon, -1, (0, 0, 255), 2)  # 筛选合适的轮廓,通过经验获得筛选参数值,每个轮廓都可以w,h打印后观察。 losc = [] for con in gradcon:     (x, y, w, h) = cv2.boundingRect(con)     ar = w/h     #print(x,y,w,h)     if ar > 2.4 and ar < 3.5:         if w > 155 or w < 85:             continue         losc.append((x,y,w,h)) # 根据坐标对矩形包围框进行排序,排序目的和前面对模板数字图片的排序目的相同。  sort_losc = sorted(losc, key=lambda x: x[0], reverse=False)  img_part = [] for i in sort_losc:     x, y, w, h = i[0], i[1], i[2], i[3]     con = np.array([[[x, y],[x w, y], [x w, y h], [x, y h]]])     img_part.append(img_card[y:y h, x:x w])     # cv2.imshow('7', img_card[y:y h, x:x w])  # 接下来,获取每个数字。 digital = [] def f(img):     img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)     img_2 = cv2.threshold(img_gray, 0, 255, cv2.THRESH_OTSU)[1] #    可以先获得轮廓Canny检测,再画轮廓,也可以先求梯度。 #    轮廓可以在这里直接找到,因为我们需要找到的是每个数字的轮廓,每个数字都是连接的      imgcon = cv2.findContours(img_2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]     new_con = []      # 筛选     for con in imgcon:         (x, y, w, h) = cv2.boundingRect(con)         if h > 35 or w < 15:             continue         new_con.append((x,y,w,h))      # 排序,类似于前面的目的     sort_con = sorted(new_con,key = lambda x:x[0])      for i in sort_con:         x, y, w, h = i[0], i[1], i[2], i[3]         con = np.array([[[x, y], [x w, y], [x w, y h], [x, y h]]])         roi = img_2[y-1:y h 1, x-1:x w 1]         # 注意数字图片区域和模板图片区域的大小         digital.append(cv2.resize(roi, (57, 88)))  for i in img_part:     f(i)  # 模板匹配接下来 lst_2 = [] for img_dig in digital:     now = []     for (dig, digroi) in digits.items():         res = cv2.matchTemplate(img_dig, digroi, cv2.TM_CCOEFF_NORMED)         now.append(res.item())     lst_2.append(now.index(max(now)))     now.clear()  print(lst_2) 

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章