实现效果:
code
import cv2 as cv
import numpy as np
# 轮廓排序 默认从左到右
# --cnts 待排序的轮廓列表
# --method 排序方法 自上而下,从左到右等
def sort_contours(cnts, method="left-to-right"):
# 初始化反向标志和排序索引
reverse = False
i = 0
# 处理是否需要逆向排序
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
# 处理时根据边界框的x坐标排序还是y坐标排序,如果是自上而下或者自下而上则需要根据y坐标排序而不是x坐标
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
# 构建边界框list 并使用python魔术lambda表达式进行排序
boundingBoxes = [cv.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b[1][i], reverse=reverse))
# 返回排序后的轮廓和边界框
return (cnts, boundingBoxes)
# 显示图像
def cv_show(name, img):
cv.imshow(name, img)
# cv.waitKey(0)
# cv.destroyAllWindows()
# =================================1.读入模板图像================================
def loadTemplate():
img = cv.imread('template.png')
cv_show('src', img)
# 灰度图
ref = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv_show('gray', ref)
# 二值化
ref = cv.threshold(ref, 10, 255, cv.THRESH_BINARY_INV)[1]
cv_show('binary', ref)
# 计算轮廓 外轮廓
refCnts, hierarchy = cv.findContours(ref.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
print(np.array(refCnts).shape)
# print('---contours', contours)
# -1画所有的轮廓
cv.drawContours(img, refCnts, -1, (0, 255, 0), 3)
cv_show('canny', img)
digits = {}
# 对轮廓进行排序
refCnts = sort_contours(refCnts)[0]
#
# 模板值的对应
for (i, c) in enumerate(refCnts):
(x, y, w, h) = cv.boundingRect(c)
# print(i, ":", (x, y, w, h))
roi = ref[y:y + h, x:x + w]
roi = cv.resize(roi, (57, 88))
# cv_show('roi',roi)
digits[i] = roi
return digits
# ==========================2.读入输入图像进行处理===============================
def dealProcess(digits):
# 初始化卷积核
rectKernel = cv.getStructuringElement(cv.MORPH_RECT, (9, 3))
sqKernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
src = cv.imread('card.png')
cv_show('src', src)
inGray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
cv_show('inGray', inGray)
# 礼帽操作
tophat = cv.morphologyEx(inGray, cv.MORPH_TOPHAT, rectKernel)
cv_show('tophat', tophat)
# ksize=-1 3X3
gradX = cv.Sobel(tophat, ddepth=cv.CV_32F, dx=1, dy=0, ksize=-1)
gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / maxVal - minVal))
gradX = gradX.astype("uint8")
cv_show('gradX', gradX)
# 闭操作
gradX = cv.morphologyEx(gradX, cv.MORPH_CLOSE, rectKernel)
cv_show('MORPH_CLOSE', gradX)
# 自动寻找合适的阈值
thresh = cv.threshold(gradX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
cv_show('thresh', thresh)
thresh = cv.morphologyEx(thresh, cv.MORPH_CROSS, sqKernel)
cv_show('thresh-close', thresh)
# 计算轮廓
srcCnts, srcHierarchy = cv.findContours(thresh.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
print(type(srcCnts))
src2 = src.copy()
cv.drawContours(src2, srcCnts, -1, (0, 255, 0), 3)
cv_show('src', src2)
locs = []
for (i, c) in enumerate(srcCnts):
(x, y, w, h) = cv.boundingRect(c)
ar = w / float(h)
# print(i, ":","rect->",(x, y, w, h), ar)
if 2.8 < ar < 4.0:
if (50 < w < 65) and (15 < h < 33):
locs.append((x, y, w, h))
locs = sorted(locs, key=lambda x: x[0])
print('-------------------------')
print(locs)
output = []
for (i, (gX, gY, gW, gH)) in enumerate(locs):
groupOutput = []
# 截取图像
group = inGray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
# cv_show('group', group)
# 预处理 二值化
group = cv.threshold(group, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]
cv_show('group', group)
# 计算一组轮廓
digitCnts, hierarchy = cv.findContours(group.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
digitCnts = sort_contours(digitCnts)[0]
# 计算每一组中每一个数值
for c in digitCnts:
# 找到当前数值轮廓,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)
# 相关系数
(minVal, maxVal, minLoc, maxLoc) = cv.minMaxLoc(result)
scores.append(maxVal)
# print(maxVal)
# 得到合适的数字
groupOutput.append(str(np.argmax(scores)))
cv.rectangle(src, (gX - -5, gY - 5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
cv.putText(src, "".join(groupOutput), (gX, gY - 15), cv.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)
# 得到结果
output.extend(groupOutput)
return (src, output)
if __name__ == '__main__':
digits = loadTemplate()
(src, output) = dealProcess(digits)
# 打印输出结果
print("res:{}".format("".join(output)))
cv_show('res', src)
cv.waitKey()
用到的资源图片:
感谢支持,欢迎讨论交流,谢谢!