10.银行卡号识别

目录

1  项目介绍

2  代码实现

2.1  导入库

2.2  设置参数

2.3  定义银行卡信息

2.4  定义显示图片函数

2.5  处理模板

2.5.1  读入图片

2.5.2  灰度处理

2.5.3  二值处理

2.5.4  轮廓检测

2.5.5  轮廓排序

2.5.6  把模板中每一个数字分别切出来

2.6  处理图像

2.6.1  初始化卷积核

2.6.2  读取图像

2.6.3  调整图像尺寸

2.6.4  使图像变为灰度图

2.6.5  礼帽操作

2.6.6  计算横向梯度

2.6.7  闭运算

2.6.8  二值处理

2.6.9  再次进行闭操作

2.6.10  计算轮廓

2.6.11  过滤轮廓

2.6.12  轮廓排序

2.6.13  对轮廓中的内容再进行轮廓检测


1  项目介绍

我们现在有一张银行卡

我们还有一个模板

效果是这样的

我们切出银行卡上的每一个数字的区域,然后与我的模板进行匹配,匹配之后会得到与模板最像的区域,模板不同的区域就代表着不同的数字,这样就识别出来了

图像处理的流程不唯一,我们当遇到其他项目问题的时候应该对着之前讲过的方法看一下,看看哪一种最合适

并不是所有银行卡都能通用的,如果要找通用的还是要使用人工智能算法


2  代码实现


2.1  导入库

首先我们导入库

  • imutils这个包依赖numpy,opencv与matplotlib 是另一个做图像处理的库
  • argparse 添加参数用的

此处导入的myutils并不是网上pip install的包,而是一个文件,文件内容如下

  • myutils
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

内容是基于opencv的两个方法,我们把以上代码存储为一个py文件,在主文件中就可以导入了,后面用的时候会提到


2.2  设置参数

我们有两个参数 -i 是我们要识别的图像,-t是我们要使用的模板

前面的-i,--image是要在控制台中输入字符后,然后输入变量,就像这样

或者这样

这样我们就能使用这个变量了,help是当用户在使用时输入-h或--help可以查看的字符串

required如果为True,那么代码将只能在终端加入变量且无法使用默认值,当我们调试的时候每次都打开终端是比较麻烦的,所以是需要有默认值的,我们先给它置为False,然后给两个参数分别添加默认值

最下面的args = vars(ap.parse_args()是把获得的参数整合到一起,有两种写法,例子中是第一种,我们看一下打印出来会是什么东西

是根据--后的值创建的键值对

我们再看一下第二种,我把参数名称换一下以印证我刚刚的说法

他们的调用方式不一样

我们在案例中为与视频保持一致所以选用带vars的方法


2.3  定义银行卡信息

创建一个键值对,键值对的内容是每一种银行卡

2.4  定义显示图片函数

定义一个显示图片的函数,在过程测试中会多次显示图片,我们使用定义的函数会减少很多代码量

2.5  处理模板


2.5.1  读入图片

我们先看一下模板

2.5.2  灰度处理

确认是这张图后对其进行灰度处理

虽然看着差不多,但是确实通道变化了


2.5.3  二值处理

小于10的值我们改为255,大于10的值我们改为0,由于图像中只有黑与白,所以我们相当于对图像做了一个反色

后面的[1]是这样的,我们之前是这样调用的

现在我们只把结果赋值给了一个变量,所以赋值的变量就会是一个元组,我们取元组的第一位展示出来

2.5.4  轮廓检测

检测之后把所有轮廓画出来

  • cv2.RETR_EXTERMAL是只检测外轮廓
  • cv2.CHAIN_APPROX_SIMPLE 是保留坐标点

我们查看一个轮廓总数

发现总数是10个,之后我们使用myutils对这十个轮廓从左到右进行排序


2.5.5  轮廓排序

我们现在进入myutils看一下这个排序是怎么做的

首先看参数,cnts轮廓集合,method方法,这个是排序的方向,恶意是左到右,右到左,下到上,上到下

之后定义变量reverse,起始值为False,也就是不反向,定义变量i,起始值为1

之后对方法种类进行判定

  • 如果是右到左或者下到上,reverse为True(设置为反向)
  • 如果是上到下或下到上,i为1

我们使用的是左到右,所以不走这两个判定,所以我们当前的reverse为False,i为0,然后我们继续看中括号中的内容

遍历每个边界,然后对每一个边界执行boundingRect()

,boundingRect()之前介绍过,是轮廓的外接矩形,它会返回一个元组,元组中有x,y,w,h四个变量

之后我们再看这一整句,这样写的意思是将每一个轮廓返回来的每一个元组作为元素,形成一个列表,然后赋值给boundingBoxes

也就是说现在 boundingBoxes 是一个有轮廓外接矩形信息的元组列表

现在只剩最后一句了,我们拆解来看,先看紫色框的zip(cnt,boundingBoxes),这个是意思是将所有轮廓与(x,y,w,h)打包在一起,由于我们之前每动过顺序,所以cnts与(x,y,w,h)是一一对应的

那么执行完上面一句,我元组应该是这样的(cnt,x,y,w,h),其中x,y,w,h是浮点型数据,cnt是每一个轮廓,我们打印cnts中的第0位出来看一下,

我们可以看到cnt也是一个列表,所以我们的zip(cnts,boundingBoes)实际上是这样的 ([cnt],(x,y,w,h))

我们再看第二个小括号也就是蓝色的区域,使用sorted对刚刚压缩的东西进行排序,然后排序方式(key)定义为b,冒号后面没有语句,直接进行选择,这个代表b就是要排序对象本身,启用本身的1号为元素(x,y,w,h)中的第i(0)个元素(x)进行排序,不进行反向

这样我们就得到了以x值为顺序的一组(([cnt],(x,y,w,h)),([cnt1],(x1,y1,w1,h1)),...,([cnt10],(x10,y10,w10,h10))

最后一步,使用匹配压缩,再给cnts,和boundingBoxes整成一堆

我们可以看一下这个

zip(*)会抽取每一个元组中的第一个值然后捏在一起,然后抽第二个值然后捏在一起,直到抽完,我们例子中是先抽第一个值(cnt),然后捏在一起(cnts),再抽第二个值(x,y,w,h),然后捏在一起boundingBoxes

捏在一起的意义在于后面就可以根据索引调用了,而且现在的第0位就是0的轮廓,第一位就是1的轮廓

然后我们会到我们的主函数中来

执行完后,发现我们取第0号元素,也就是排好序的cnts


2.5.6  把模板中每一个数字分别切出来

首先定义一个空的字典digits,这个一会儿要用

之后遍历轮廓,此处我的c是单一的轮廓,i是c这个轮廓对应的索引,现在我们排序完毕了,那么0的轮廓就是0号索引

进入循环后,找到每一个轮廓的外接矩形,然后把该矩形中的模板图片提取出来,ref是我们二值后的模板图片

我们以第一遍的遍历距离,遍历到0了,把0的图片提取出来,此时的roi

然后我们将索引与图像放到digits中,也就是我现在的digits是这样的

  • 0:

  • 1:

我就不一一展示了,一直到9,一共十个,至此我们对处理完了模板


2.6  处理图像

由于卡上不只有数字,所以我们要处理图像排除其他东西的影响


2.6.1  初始化卷积核

cv2,getStructuringElement是cv2中定义核的一个函数,下面我说一下这个函数的几个参数

  • MORPH_RECT 这个代表这个核是矩形的,我们还可以定义为交叉形MORPH_CROSS与椭圆形MORPH_ELLIPSE
  • 核的大小,我当前是(9,3)和(5,5)根据任务不同选择合适的大小
  • 锚点,这个在我上面没用,默认为(-1,-1)中心点即为锚点,以后用到会再提

2.6.2  读取图像

2.6.3  调整图像尺寸

此处我们使用myutils中的第二个方法resize

首先定义dim为None,然后获取图片的高与宽,我们是给定width为300的,所以我们直接进入else,定义r = width/原宽度,这个r就是现有图与原有图的横向比例,然后定义dim = (现有图宽度,现有图高度(我们使用原有图高度*横向比例),这个dim是做了一个等比例缩放,之后使用cv2.resize,resize中interpolation可以选择不同的插值方法,有五种插值方法,如下所示

关于插值如果想详细的了解可以看一下这个计算机视觉基础-图像插值算法_CleMints的博客-CSDN博客

我们当前的inter是cv2.INTER_AREA

2.6.4  使图像变为灰度图

2.6.5  礼帽操作

使用的是我们定义的(9,3)的矩形核

2.6.6  计算横向梯度

ksize = -1标识采用默认值,默认值为(3,3)

  • 取绝对值

  • 获取最大值与最小值

  • 归一化

  • 改变图像类型为uint8,因为我之前深度是CV_32F,现在转换回来

  • 展示出来

2.6.7  闭运算

2.6.8  二值处理

cv2.THRESH_OTSU的意思是,opencv会自动判断一个合适值来代替0,因为我现在也不知道这个像灰色的颜色的值是多少,所以就交给计算器去自动判断

2.6.9  再次进行闭操作

目的是把区域中这些黑色填充成白色

这次使用的是之前定义的sqKernel核,视频中没有写迭代次数,我在这迭代两次,感觉效果要更好些

2.6.10  计算轮廓

使用上面的结果找到轮廓后画在原本的图上,之后显示出来

2.6.11  过滤轮廓

我们实际就是要白色区域内的轮廓,其余轮廓全都不要

这四个轮廓我们可以通过边界矩形的长宽比进行判断

首先创建一个空列表locs,然后获取所有的轮廓外接矩形,之后对每一个矩形计算长宽比,我当前这四个轮廓的长宽比区间在2.5与4之间,过滤掉一部分之后,我们在进行一次过滤筛掉与这四个相似的,我们定义宽度在40-55之间,高度在10-20之间的为我们想要的轮廓

显示出来发现有四个合适的轮廓

2.6.12  轮廓排序

之后我们再利用(x,y,w,h)中的x这个值进行排序

2.6.13  对轮廓中的内容再进行轮廓检测

我们先定义一个空列表output,这个后面会用

然后遍历这四个轮廓,之后再定义一个空列表groupOutput,之后有用,之后提取原始灰度图中的外接轮廓位置图像

发现没有什么问题,之后对这四张图进行二值处理

然后对这四张照片检测轮廓,之后排序

这样我们就得到了最内层数字的轮廓,比如4000中的4,这个时候我们提取轮廓矩形,然后从上面四张图中切下来

  • 注意,这个循环是嵌套在上面的大循环中的

第一组

第二组

第三组

第四组

之后进行模板匹配

roi是被检测图像这种图

digitROI是模板种的这种图

我们只对最大值(最像的值)感兴趣,其余变量我不需要,所以用_直接替代掉,它原本的四个变量应该是这样

然后我们把最大的值放入列表scores中

此时我们的scores是这样的

由于我再每次大循环中都会重新将scores赋值为空,所以我们只能看到四个,我们看到的这四个是最后一组的情况,它使用图中的roi去核digitROI对10次,每一次都会出现一个值,一次类推,第一个会出现10个值,第二个也会出现10个值

我们现在取每10个值中最大的一个值的索引放入groupOutPut中

然后我们画上框,写上字

putText中的0.65是字号,2是线条宽度

我们可以把每一轮的索引搞出来,最后打印出来

我们最后再做一些处理,我们可以通过output的第0位判断银行卡是何种类型4是viso,然后我们在末尾将结果显示出来

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Suyuoa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值