(1)引入模块
import cv2
import numpy as np
import myutils
(2)图像的基本操作
1.图像读取
img=cv2.imread("路径")
2.图像显示
cv2.imshow("窗口名",图像变量(img))
(3)图像的轮廓检测
1.图像的灰度化
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
或直接img=cv2,imread("路径",0)
2.图像的二值化(黑白图像)
ref=cv2.threshold(gray,10,255,cv2.THRESH_BINARY_INV)[1]
10,255:表示阈值(超过10取255,小于取0)
cv2.THRESH_BINARY_INV表示取法相反
3.寻找轮廓
refCnt,hierarchy=cv2.findContours(ref,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
ref表示在轮廓检测中要用二值图像
cv2.RETR_EXTERNAL只寻外轮廓
draw_refCnt=cv2.drawContours(img.copy(),refCnt,-1,(0,0,255),3)
img.copy()为在画轮廓时不印象原图
reCnts表示轮廓
-1表示所有的轮廓
3表示通道3
结果:
4.模块轮廓划分和排序
1.refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
将数字模板每个数字的轮廓计算出来,并且排序,reCnts可以看做轮廓合集
2.遍历每个轮廓,得到模块
for (i,c) in enumerate (reCnts)://遍历每个轮廓
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
(x,y,w,h)=cv2.boundingrect(c)//获得轮廓的外接矩形,返回元组矩形左上坐标和矩阵长宽
roi=ref[x:x+w, y:y+h]//获得roi感兴趣部分
roi=cv2.resize(58,88)//转化大小适用于模板匹配
4.定义卷积核
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
5.读入银行卡图像,预处理(使其可以更准确)
1.img2=cv2.imread("绝对路径")
img2=myutils.resize(img2,width=300)//把宽变为300,其高转变为对应的长度
gray=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)//灰度化
tophat=cv2.morphologyEx(gray,MORPH_TOPHAT,rectKernel)//礼帽处理,使图像变得更加明亮
6.sobel算子
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)# ksize=-1相当于用3*3的
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('gradX', gradX)
sobel算子作用:Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
7.进行闭运算【先腐后膨】(对输入图像没有规定(灰度图和二值图像))
gradx=cv2.morphologyEX(gradX,0,255,cv2.MORPH_CLOSE,rectKernel)
作用:使图像中的孔隙填充(先对图像膨胀后腐蚀 作用:用来填充物体内的小空洞,连接邻近的物体,连接断开的轮廓线,平滑其边界的同时不改变面积)
8.二值化cv2.threshold
# THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
9.在进行一个闭运算
thresh=cv2.morphologyEX(thresh,0,255,cv2.MORPH_CLOSE,rectKernel)
10.寻找轮廓
threshcnts,hierarchy=cv2.foundContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=theshcnts
11.遍历轮廓数字组
locs=[]
for(i,c) in enumerate(cnts):
(x,y,w,h)=cv2.boundingRect(c)
ar=w/float(h)
# 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
if ar >2.5 and ar <4.0://根据实际大小比例
if (w >40 and w <55)and (h >10 and h <20):
# 符合的留下来
locs.append((x, y, w, h))
# 将符合的轮廓从左到右排序(轮廓没有顺序,需要人为排序)
locs =sorted(locs, key=lambda x: x[0])
output = []
12.遍历数字轮廓(每个数字组中数字)
for(i,(gx,gy,gw,gh)) in enumberate(locs):
groudOutput=[]//定义一个list
# 根据坐标提取每一个组
group = gray[gY -5:gY + gH +5, gX -5:gX + gW +5]//截取灰度图像
cv_show('group', group)
# 预处理
group = cv2.threshold(group, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('group', group)
# 计算每一组的轮廓
digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)//轮廓检测
digitCnts = myutils.sort_contours(digitCnts,method="left-to-right")[0] //为数字组中每个数字轮廓排序
for (c) in (digitCnts):
(x,y,w,h)=cv2.boundingRect(c)
roi=(y:y+h,x:x+w)
roi=cv2.resize(roi,(58,88))
# 计算匹配得分
scores = []
# 在模板中计算每一个得分
for (digit, digitROI)in digits.items()://item()方法把字典中每对key和value组成一个元组,并把这些元组放在列表中返回。digit为key,digitROI为value
# 模板匹配
result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF_NORMED))#TM_CCOEFF_NORMED,1表示完美的匹配;-1表示最差的匹配。即表示越大越好
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)//#result参数表示匹配结果图像,必须是单通道32位浮点,scorce参数表示返回的最大值//score可以大致认为匹配度,匹配度越大,越准确
# 得到最合适的数字
groupOutput.append(str(np.argmax(scores)))//#numpy.argmax(array, axis) 用于返回一个numpy数组中最大值(最大可能性)的索引值(下标)
# 画出来
cv2.rectangle(img2, (gX -5, gY -5),(gX + gW +5, gY + gH +5), (0, 0, 255), 1)
cv2.putText(img2, "".join(groupOutput), (gX, gY -15),cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
cv2.putText(img, str(i), (123,456)), font, 2, (0,255,0), 3)
各参数依次是:图片,添加的文字,左上角坐标,字体,字体大小,颜色,字体粗细
Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串
print("Credit Card #: {}".format("".join(output)))//数字识别结果
cv2.imshow("Image", img2)
cv2.waitKey(0)
附言:这个小项目网上已经有许多源代码(本文只是代码简单说明),本博客只是自己对这个项目的理解,希望对读者有点帮助
银行卡图片:
模板图片: