You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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)

现存问题

  • 部分棋子未被模板匹配到
  • 不知道如何将匹配到的棋子按棋盘位置分组统计数量

技术解决方案

一、解决模板漏匹配问题

  1. 多模板匹配
    棋子存在角度、光照、缩放差异时,单模板易漏检。制作多个角度(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]))
    
  2. 结合轮廓检测预处理
    重叠棋子会导致模板匹配失效,先通过二值化提取棋子轮廓过滤干扰:

    _, 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]
    
  3. 颜色分割辅助
    利用棋子颜色差异(黑/白)先提取对应颜色区域,再在区域内做匹配或检测,减少背景干扰。

二、按棋盘位置统计棋子数量

  1. 建立棋盘位置坐标映射
    手动标记或计算棋盘24个位置的坐标范围,建立位置编号与区域的对应关系:

    board_positions = {
        "1": (50, 150, 50, 150),
        "6": (400, 500, 50, 150),
        # 补充其他22个位置的坐标范围
    }
    
  2. 匹配结果分组计数
    遍历匹配坐标,判断所属位置并统计数量:

    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 对应黑棋位置}
    }
    
  3. 聚类自动分组
    若手动标记坐标麻烦,用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:40:58