跟着b站教程学习p36-p40:
https://www.bilibili.com/video/BV1RQ4y1R7M6?p=40
感觉意义不大,一般用不到这些东西。
抄的视频内容,本来不该写原创,但是不想联系作者,而且链接不知该怎么放,联系侵权自删
import
import imutils
import argparse
import cv2 as cv
import myutils
import numpy as np
能import的代码绝不自己写
下载的myutils中没有conunders,所以自己抄了个
def sort_contours(cnt, method="left-to-right"):
reverse = False
i = 0
if method == "left-to-right" or method == "bottom-to-top":
i = 1
boundingBoxes = [cv.boundingRect(c) for c in cnt]
# 用一个最小的矩形,将找到的形状包起来x,y,h,w
(cnt, boundingBoxes) = zip(*sorted(zip(cnt, boundingBoxes), key=lambda b: b[i], reverse=reverse))
return cnt, boundingBoxes
框架就不细分了,直接上整体的代码,不过也都是跟着教程打上去的,没啥自己写的东西。
"""
配置参数:右键 -configurations-parameters:
--image images/credit_test.png # 测试图片
--template images/credit_mo.png # 母版
"""
# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="test image path")
ap.add_argument("-t", "--template", required=True, help="mother image path")
args = vars(ap.parse_args())
# 指定信用卡类型
FIRST_NUMBER = {
"3": "American Express",
"4": "Visa",
"5": "MasterCard",
"6": "Discover Card"
}
# 绘图展示
def cv_show(name, src_img):
cv.imshow(name, src)
cv.waitKey(0)
cv.destroyAllWindows()
src = cv.imread(args["template"]) # 读取一个模板图像
ref = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
ref = cv.threshold(ref, 10, 255, cv.THRESH_BINARY_INV)[1] # 二值化
# 计算轮廓
refCnt, hierarchy = cv.findContours(ref.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
cv.drawContours(src, refCnt, -1, (0, 0, 255), 1) # 绘制轮廓
# 轮廓排序
refCnt = myutils.sort_contours(refCnt, method="left-to-right")[0] # 排序,从左到右,从上到下,import
digits = {}
# 模板制作,i表示轮廓索引,c表示找到的轮廓
for (i, c) in enumerate(refCnt):
# 计算外接矩形并且resize成合适大小 ,x,y表示矩形的起点坐标,w,h,表示矩形的长宽
(x, y, w, h) = cv.boundingRect(c)
roi = ref[y:y + h, x:x + w]
roi = cv.resize(roi, (57, 88))
digits[i] = roi
# 初始化卷积核,核大小自己指定,与任务有关
rectKernel = cv.getStructuringElement(cv.MORPH_RECT, (9, 3))
sqKernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
# 读取输入图像,预处理
img = cv.imread(args["image"]) # ???
# 重新设置输入图片的大小
image = imutils.resize(img, width=300)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
# 礼帽操作,突出更明亮的区域
top_hat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, rectKernel)
# sobel 算子,只有x效果比x+y效果好
gradX = cv.Sobel(top_hat, ddepth=cv.CV_32F, dx=1, dy=0, # -1,3*3
ksize=-1)
gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")
# 通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv.morphologyEx(gradX, cv.MORPH_CLOSE, rectKernel)
# OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv.threshold(gradX, 0, 255,
cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
# 闭操作
thresh = cv.morphologyEx(thresh, cv.MORPH_CLOSE, sqKernel)
threshCnt, hierarchy = cv.findContours(thresh.copy(), cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE)
cnt = threshCnt
cur_img = image.copy()
# 画出找到的待匹配图像轮廓
cv.drawContours(cur_img, cnt, -1, (0, 0, 255), 3)
# 存储符合条件的轮廓信息
loc = []
# 遍历轮廓
for (i, c) in enumerate(cnt):
# 计算矩形
(x, y, w, h) = cv.boundingRect(c)
ar = w / float(h)
# 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
if 2.5 < ar < 4.0:
if (40 < w < 55) and (10 < h < 20):
# 符合的留下来
loc.append((x, y, w, h))
# 将符合的轮廓从左到右排序
loc = sorted(loc, key=lambda x1: x1[0])
output = []
# 遍历每一个轮廓中的数字,索引及详细信息
for (i, (gX, gY, gW, gH)) in enumerate(loc):
groupOutput = []
# 根据坐标提取每一个组,将每一组的轮廓适当的上下左右均扩大
group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
# 预处理,自动进行分割
group = cv.threshold(group, 0, 255,
cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
# 计算每一组的轮廓,同上,计算外部轮廓及位置信息
digitCnt, hierarchy = cv.findContours(group.copy(), cv.RETR_EXTERNAL,
cv.CHAIN_APPROX_SIMPLE)
digitCnt = myutils.sort_contours(digitCnt,
method="left-to-right")[0]
# 计算每一组中的每一个数值
for c in digitCnt:
# 找到当前数值的轮廓,resize成合适的的大小
(x, y, w, h) = cv.boundingRect(c)
roi = group[y:y + h, x:x + w]
roi = cv.resize(roi, (57, 88))
# 计算匹配得分,计算每一个数字与模板中数字相匹配的得分
scores = []
# 在模板中计算每一个得分
for (digit, digitROI) in digits.items():
# 模板匹配
result = cv.matchTemplate(roi, digitROI,
cv.TM_CCOEFF)
(_, score, _, _) = cv.minMaxLoc(result)
scores.append(score)
# 得到最合适的数字
groupOutput.append(str(np.argmax(scores)))
# 画出来
cv.rectangle(image, (gX - 5, gY - 5),
(gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
cv.putText(image, "".join(groupOutput), (gX, gY - 15),
cv.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)))
cv.imshow("Image", image)
cv.waitKey(0)
cv.destroyAllWindows()