一、传参方法
使用库:argparse
python
cuancan=argparse.ArgumentParser()
-
argparse.ArgumentParser是一个类 -
argparse.ArgumentParser()是调用该类的构造函数 -
创建了一个 ArgumentParser 类的实例对象,并赋值给变量
cuancan
python
cuancan.add_argument('--a',type=int,default=20,help='物体的高')
cuancan.add_argument('--b',type=int,default=80,help='物体的长')
cuancan.add_argument('-c','--c',type=float,default=31.8,help='物体的宽')
使用add_argument想cuancan中添加一些参数
参数解释:
1. '-c', '--c' - 多个参数名称(短选项+长选项)
-
-c:短选项-
单字符,使用单横线
-
简洁方便,适合常用选项
-
-
--c:长选项-
多字符(这里也是单字符,但格式是长选项)
-
更易读,适合脚本中使用
-
-
作用 :用户可以使用
-c或--c来指定该参数
2. type=float - 参数类型
- 作用:将输入值转换为浮点数
3. default=31.8 - 默认值
-
作用:用户未提供时的默认值
-
注意 :默认值类型要与
type匹配
4. help='物体的宽' - 帮助信息
- 作用:在帮助文档中显示描述
python
opt=cuancan.parse_args()
h=opt.a
l=opt.b
w=opt.c
print('物体的体积:',h*l*w)
opt = cuancan.parse_args() 是 解析命令行参数 的关键语句
-
cuancan:之前创建的ArgumentParser对象 -
.parse_args():调用该对象的parse_args()方法 -
opt:将解析结果赋值给变量opt(通常命名为args)
将参数a、b、c的值赋值给h、l、w,输出h*l*w的值
1)使用代码的默认值运行:

2)右击鼠标



3)点击软件下方终端,进入终端模式



二、银行卡识别案例
任务书:要为某家银行设计一套智能卡号识别的系统。
要求:传入一张图片,就自动输出信用卡图片中的数字
1)模板预处理
python
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]
(cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),
key=lambda b:b[1][i],reverse=reverse))
#zip(*...) 使用星号操作符解包排序后的元组列表,并将其重新组合成两个列表:一个包含所有轮廓,另一个包含所有边界框。
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) #默认为cv2.INTER_AREA,即面积插值,适用于缩放图像。
return resized
下个代码中使用的 import myutils中myutils是这个代码的文件名
python
import numpy as np
import argparse # python内置库
import cv2
import myutils
# 设置参数
ap = argparse.ArgumentParser() # 创建 ArgumentParser 对象,这个对象将用于定义和解析命令行参数
ap.add_argument("-i", "--image", required=True, help="path to input image")
ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image")
args = vars(ap.parse_args()) # vars()是Python中的一个内置函数,用于返回对象的属性和值的字典。
# 指定信用卡类型
FIRST_NUMBER = {
"3": "American Express",
"4": "Visa",
"5": "MasterCard",
"6": "Discover Card"
}
def cv_show(name, img): # 绘图展示
cv2.imshow(name, img)
cv2.waitKey(0)
# ... 模板图像中数字的定位处理......
img = cv2.imread(args["template"])
cv_show('img', img)
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度图
cv_show('ref', ref)
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1] # 二值图像 黑底白字,方便找轮廓
cv_show('ref', ref)
# 计算轮廓: cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),
# cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
# refCnts, hierarchy = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#opencv是3点几版本,所以要使用下面的
# 将第 38 行改为:
_, refCnts, hierarchy = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)
cv_show('refCnts', img)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] # 排序,从左到右,从上到下
digits = {} # 保存模板中每个数字对应的像素值
for (i, c) in enumerate(refCnts): # 遍历每一个轮廓
(x, y, w, h) = cv2.boundingRect(c) # 计算外接矩形并resize成合适大小
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (57, 88)) # 缩放到指定的大小
cv_show('roi', roi)
digits[i] = roi # 每一个数字对应每一个模板
print(digits)

2)银行卡图形处理
python
image=cv2.imread(args['image'])
cv_show('image',image)
image=myutils.resize(image,width=300)
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)
#图形形态学
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
#顶帽操作
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('tophat',tophat)
#闭操作
close1=cv2.morphologyEx(tophat,cv2.MORPH_CLOSE,rectKernel)
cv_show('close1',close1)
#二值化
thresh=cv2.threshold(close1,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh)
#闭操作
close2=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,rectKernel)
cv_show('close2',close2)
#轮廓检测
_,cnts,h=cv2.findContours(close2.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts_img=image.copy()
cv2.drawContours(cnts_img,cnts,-1,(0,0,255),3)
cv_show('cnts_img',cnts_img)

python
locs=[]
for c in cnts:
(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))
# if (100<y<105)and(10<h<20):
# locs.append((x,y,h,w))
locs=sorted(locs,key=lambda x:x[0])
print(locs)
筛选所需要的轮廓

3)模板匹配
python
output = []
# 遍历每一个轮廓中的数字
for (gx, gy, gw, gh) in locs:
groupOutput = []
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)
# 计算每一组的轮廓
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:
# 找到当前数值的轮廓,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', roi)
'''---使用模板匹配,计算匹配得分---'''
scores = []
# 在模板中计算每一个得分
for (digit, digitROI) in digits.items():
# 模板匹配
result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)
# 得到最合适的数字
groupOutput.append(str(np.argmax(scores)))
# 画出来
cv2.rectangle(image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)
cv2.putText(image, "".join(groupOutput), (gx, gy - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
output.extend(groupOutput) # 得到结果 将一个列表的元素添加到另一个列表的末尾。
# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow('images',image)
cv2.waitKey(0)
cv2.destroyAllWindows()


注:使用的模板大小,要和进行识别的图片中对应的图片大小一致,并且在进行二值化是,要使用同样的阈值类型标志
在运行这个代码的时候,会出现下图情况

是因为这时候没有给参数赋值,要先赋值再运行
三、身份证识别
由于和银行卡识别类似,这里我就只放了代码部分
python
'''第一种方法'''
import argparse # python内置库
import cv2
import myutils
import numpy as np
# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to input image")
ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image")
args = vars(ap.parse_args())
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
# 模板处理...
img = cv2.imread(args["template"])
cv_show('img', img)
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref', ref)
ref = cv2.threshold(ref, 150, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref', ref)
_, refCnts, hierarchy = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, refCnts, -1, (0, 255, 0), 2)
cv_show('refCnts', img)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
digits = {}
for (i, c) in enumerate(refCnts):
(x, y, w, h) = cv2.boundingRect(c)
roi = ref[y-2:y + h+2, x-2:x + w+2]
roi = cv2.resize(roi, (57, 88))
cv_show('roi', roi)
digits[i] = roi
cv2.destroyAllWindows()
# 加载身份证图像
image = cv2.imread(args['image'])
cv_show('image', image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray', gray)
# 增强对比度
# clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(6, 6))
# gray_enhanced = clahe.apply(gray)
# cv_show('gray_enhanced', gray_enhanced)
# 二值化
# _, thresh_inv = cv2.threshold(gray_enhanced, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
# cv_show('thresh_inv', thresh_inv)
thresh = cv2.threshold(gray, 120,255, cv2.THRESH_BINARY_INV)[1]
cv_show('adaptive_thresh', thresh)
# 查找轮廓
_, cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
a=cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 2)
cv_show('all_contours', a)
# 筛选身份证号码区域的轮廓
locs=[]
for c in cnts:
(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))
if (x>220)and(330<y<360):
locs.append((x,y,w,h))
locs=sorted(locs,key=lambda x:x[0])
print(locs)
output = []
# 遍历每一个轮廓中的数字
for (i,(gx, gy, gw, gh)) in enumerate(locs):
groupOutput = []
group = gray[gy - 2:gy + gh + 2, gx - 2:gx + gw + 2] # 适当加一点边界
cv_show('group', group)
# 预处理
group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY_INV| cv2.THRESH_OTSU)[1]
cv_show('group', group)
roi = cv2.resize(group, (57, 88))
cv_show('roi', roi)
# 计算每一组中的每一个数值
'''---使用模板匹配,计算匹配得分---'''
scores = []
# 在模板中计算每一个得分
for (digit, digitROI) in digits.items():
# 模板匹配
result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
(_, score, _, _) = cv2.minMaxLoc(result) # 修正:应该是4个返回值
scores.append(score)
# 得到最合适的数字
jieguo = str(np.argmax(scores))
output.append(jieguo)
cv2.rectangle(image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)
cv2.putText(image, jieguo, (gx, gy - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
# 打印结果
print("Card ID #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()