实现效果:
code
import cv2 as cv
import numpy as np# 轮廓排序 默认从左到右
# --cnts 待排序的轮廓列表
# --method 排序方法 自上而下,从左到右等
def sort_contours(cnts, method="left-to-right"):# 初始化反向标志和排序索引reverse = Falsei = 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] = roireturn 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 3X3gradX = 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()
用到的资源图片:
感谢支持,欢迎讨论交流,谢谢!