基于OpenCV模板匹配的双陆棋棋子位置计数问题求助
双陆棋棋盘棋子统计问题
需求概述
需要分析双陆棋棋盘,输出双方玩家各位置的棋子数量,目标格式如下:
{ "o": { "6": 5, "8": 3, "13": 5, "24": 2 }, "x": { "1": 2, "12": 5, "17": 3, "19": 5 } }
相关素材
- 棋盘图片:

- 棋子模板图片:

- 当前匹配结果图片:

当前实现代码
import numpy as np from matplotlib import pyplot as plt import cv2 as cv img_rgb = cv.imread('./board.png') assert img_rgb is not None, "file could not be read, check with os.path.exists()" img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY) template = cv.imread('./black.png', cv.IMREAD_GRAYSCALE) assert template is not None, "file could not be read, check with os.path.exists()" w, h = template.shape[::-1] res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED) threshold = 0.6 loc = np.where( res >= threshold) for pt in zip(*loc[::-1]): print(pt[0] + w, pt[1] + h) cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 0) cv.imwrite('res.png',img_rgb)
现存问题
- 部分棋子未被模板匹配到
- 不知道如何将匹配到的棋子按棋盘位置分组统计数量
技术解决方案
一、解决模板漏匹配问题
多模板匹配
棋子存在角度、光照、缩放差异时,单模板易漏检。制作多个角度(0°、15°、30°)、不同缩放比例的棋子模板,分别匹配后合并结果:def rotate_template(template, angle): rows, cols = template.shape M = cv.getRotationMatrix2D((cols/2, rows/2), angle, 1) return cv.warpAffine(template, M, (cols, rows), borderValue=255) angles = [0, 15, 30] all_loc = [] for angle in angles: rotated_template = rotate_template(template, angle) res = cv.matchTemplate(img_gray, rotated_template, cv.TM_CCOEFF_NORMED) loc = np.where(res >= threshold) all_loc.extend(zip(*loc[::-1]))结合轮廓检测预处理
重叠棋子会导致模板匹配失效,先通过二值化提取棋子轮廓过滤干扰:_, binary = cv.threshold(img_gray, 127, 255, cv.THRESH_BINARY_INV) contours, _ = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) valid_contours = [cnt for cnt in contours if cv.contourArea(cnt) > 1000]颜色分割辅助
利用棋子颜色差异(黑/白)先提取对应颜色区域,再在区域内做匹配或检测,减少背景干扰。
二、按棋盘位置统计棋子数量
建立棋盘位置坐标映射
手动标记或计算棋盘24个位置的坐标范围,建立位置编号与区域的对应关系:board_positions = { "1": (50, 150, 50, 150), "6": (400, 500, 50, 150), # 补充其他22个位置的坐标范围 }匹配结果分组计数
遍历匹配坐标,判断所属位置并统计数量:from collections import defaultdict count = defaultdict(int) for pt in all_loc: x, y = pt for pos, (x_min, x_max, y_min, y_max) in board_positions.items(): if x_min <= x <= x_max and y_min <= y <= y_max: count[pos] += 1 break # 按棋子颜色拆分结果 result = { "o": {k: v for k, v in count.items() if 对应白棋位置}, "x": {k: v for k, v in count.items() if 对应黑棋位置} }聚类自动分组
若手动标记坐标麻烦,用K-means聚类将棋子坐标聚为24类,每类数量即为对应位置的棋子数:from sklearn.cluster import KMeans points = np.array(all_loc) kmeans = KMeans(n_clusters=24, random_state=0).fit(points) unique, counts = np.unique(kmeans.labels_, return_counts=True) cluster_count = dict(zip(unique, counts)) # 将聚类中心对应到棋盘位置编号
内容的提问来源于stack exchange,提问作者roglol
相关产品推荐
相关产品推荐

