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  项目介绍

我们现在有一张银行卡

10.银行卡号识别_第1张图片

我们还有一个模板

效果是这样的

10.银行卡号识别_第2张图片

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

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

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


2  代码实现


2.1  导入库

首先我们导入库

10.银行卡号识别_第3张图片

  • 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是要在控制台中输入字符后,然后输入变量,就像这样

10.银行卡号识别_第4张图片

或者这样

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

10.银行卡号识别_第5张图片

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

10.银行卡号识别_第6张图片

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

10.银行卡号识别_第7张图片

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

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

10.银行卡号识别_第8张图片

他们的调用方式不一样

10.银行卡号识别_第9张图片

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


2.3  定义银行卡信息

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

10.银行卡号识别_第10张图片

2.4  定义显示图片函数

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

10.银行卡号识别_第11张图片

2.5  处理模板


2.5.1  读入图片

我们先看一下模板

10.银行卡号识别_第12张图片

2.5.2  灰度处理

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

10.银行卡号识别_第13张图片

10.银行卡号识别_第14张图片

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


2.5.3  二值处理

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

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

10.银行卡号识别_第15张图片

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

2.5.4  轮廓检测

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

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

10.银行卡号识别_第16张图片

我们查看一个轮廓总数

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


2.5.5  轮廓排序

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

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

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

之后对方法种类进行判定

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

10.银行卡号识别_第17张图片

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

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

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

10.银行卡号识别_第18张图片

之后我们再看这一整句,这样写的意思是将每一个轮廓返回来的每一个元组作为元素,形成一个列表,然后赋值给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位出来看一下,

10.银行卡号识别_第19张图片

10.银行卡号识别_第20张图片

我们可以看到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整成一堆

我们可以看一下这个

10.银行卡号识别_第21张图片

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

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

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

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


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

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

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

10.银行卡号识别_第22张图片

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

10.银行卡号识别_第23张图片

我们以第一遍的遍历距离,遍历到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  读取图像

10.银行卡号识别_第24张图片

2.6.3  调整图像尺寸

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

10.银行卡号识别_第25张图片

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

10.银行卡号识别_第26张图片

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

我们当前的inter是cv2.INTER_AREA

10.银行卡号识别_第27张图片

2.6.4  使图像变为灰度图

10.银行卡号识别_第28张图片

2.6.5  礼帽操作

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

10.银行卡号识别_第29张图片

2.6.6  计算横向梯度

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

  • 取绝对值

  • 获取最大值与最小值

  • 归一化

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

  • 展示出来

10.银行卡号识别_第30张图片

2.6.7  闭运算

10.银行卡号识别_第31张图片

2.6.8  二值处理

10.银行卡号识别_第32张图片

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

10.银行卡号识别_第33张图片

2.6.9  再次进行闭操作

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

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

10.银行卡号识别_第34张图片

2.6.10  计算轮廓

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

10.银行卡号识别_第35张图片

10.银行卡号识别_第36张图片

2.6.11  过滤轮廓

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

10.银行卡号识别_第37张图片

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

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

10.银行卡号识别_第38张图片

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

2.6.12  轮廓排序

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

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

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

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

10.银行卡号识别_第39张图片

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

10.银行卡号识别_第40张图片

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

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

10.银行卡号识别_第41张图片

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

第一组

10.银行卡号识别_第42张图片

第二组

10.银行卡号识别_第43张图片

第三组

10.银行卡号识别_第44张图片

10.银行卡号识别_第45张图片

10.银行卡号识别_第46张图片

10.银行卡号识别_第47张图片

第四组

10.银行卡号识别_第48张图片

10.银行卡号识别_第49张图片

10.银行卡号识别_第50张图片

10.银行卡号识别_第51张图片

之后进行模板匹配

10.银行卡号识别_第52张图片

roi是被检测图像这种图

10.银行卡号识别_第53张图片

digitROI是模板种的这种图

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

10.银行卡号识别_第54张图片

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

此时我们的scores是这样的

10.银行卡号识别_第55张图片

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

10.银行卡号识别_第56张图片

10.银行卡号识别_第57张图片

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

然后我们画上框,写上字

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

10.银行卡号识别_第58张图片

10.银行卡号识别_第59张图片

10.银行卡号识别_第60张图片

10.银行卡号识别_第61张图片

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

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

10.银行卡号识别_第62张图片

你可能感兴趣的:(opencv笔记,opencv,人工智能,神经网络)