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

如何用Python OpenCV检测围棋棋盘网格并获取网格线端点?

围棋棋盘网格线合并与端点提取方案

针对HoughLinesP检测出大量碎线段的问题,核心思路是先分类横竖线,再聚类合并同方向的碎线段,最终得到完整的38条网格线(19横+19竖)并提取端点。

步骤1:提取并分类线段

先从HoughLinesP的输出中提取所有线段,再根据斜率区分横线(斜率接近0)和竖线(斜率接近无穷大):

import cv2
import numpy as np

# 假设已完成边缘检测和HoughLinesP检测
# lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=50, minLineLength=80, maxLineGap=15)
segments = [line[0] for line in lines]  # 将(1411,1,4)转换为(1411,4)的线段列表

horizontal_segs = []
vertical_segs = []

for x1, y1, x2, y2 in segments:
    dx = x2 - x1
    dy = y2 - y1
    if dx == 0:
        vertical_segs.append((x1, y1, x2, y2))
        continue
    slope = abs(dy / dx)
    # 根据斜率阈值分类,可根据实际图像调整阈值
    if slope < 0.1:
        horizontal_segs.append((x1, y1, x2, y2))
    elif slope > 10:
        vertical_segs.append((x1, y1, x2, y2))

步骤2:聚类合并同方向线段

利用K-means聚类(已知目标数量为19),将同一条网格线的碎线段归为一类,再合并得到完整线条的端点:

合并横线

from sklearn.cluster import KMeans

# 提取每条横线线段的y坐标中心
h_centers_y = np.array([(y1 + y2) / 2 for x1, y1, x2, y2 in horizontal_segs]).reshape(-1, 1)
# 聚类为19组(对应19条横线)
kmeans_h = KMeans(n_clusters=19, random_state=0).fit(h_centers_y)

# 按聚类标签分组线段
h_groups = {}
for idx, label in enumerate(kmeans_h.labels_):
    if label not in h_groups:
        h_groups[label] = []
    h_groups[label].append(horizontal_segs[idx])

# 合并每组线段,得到完整横线的左右端点
horizontal_lines = []
for group in h_groups.values():
    all_x = []
    all_y = []
    for x1, y1, x2, y2 in group:
        all_x.extend([x1, x2])
        all_y.extend([y1, y2])
    min_x = min(all_x)
    max_x = max(all_x)
    avg_y = int(sum(all_y) / len(all_y))
    # 横线端点:(左x, 平均y)、(右x, 平均y)
    horizontal_lines.append((min_x, avg_y, max_x, avg_y))

# 按y坐标排序,方便后续坐标系建立
horizontal_lines.sort(key=lambda l: l[1])

合并竖线

# 提取每条竖线线段的x坐标中心
v_centers_x = np.array([(x1 + x2) / 2 for x1, y1, x2, y2 in vertical_segs]).reshape(-1, 1)
kmeans_v = KMeans(n_clusters=19, random_state=0).fit(v_centers_x)

# 按聚类标签分组线段
v_groups = {}
for idx, label in enumerate(kmeans_v.labels_):
    if label not in v_groups:
        v_groups[label] = []
    v_groups[label].append(vertical_segs[idx])

# 合并每组线段,得到完整竖线的上下端点
vertical_lines = []
for group in v_groups.values():
    all_x = []
    all_y = []
    for x1, y1, x2, y2 in group:
        all_x.extend([x1, x2])
        all_y.extend([y1, y2])
    min_y = min(all_y)
    max_y = max(all_y)
    avg_x = int(sum(all_x) / len(all_x))
    # 竖线端点:(平均x, 上y)、(平均x, 下y)
    vertical_lines.append((avg_x, min_y, avg_x, max_y))

# 按x坐标排序
vertical_lines.sort(key=lambda l: l[0])

优化建议

  1. 预处理优化:在HoughLinesP检测前,对边缘图像做膨胀操作,减少碎线段数量:
    edges = cv2.Canny(gray, 50, 150)
    kernel = np.ones((3,3), np.uint8)
    edges = cv2.dilate(edges, kernel, iterations=1)
    
  2. HoughLinesP参数调整:增大minLineLength过滤短线段,增大maxLineGap合并距离近的线段,减少后续聚类压力。

最终得到的horizontal_lines和vertical_lines各包含19条完整网格线,每条线的四个值就是对应端点坐标,可直接用于建立(x,y)坐标系。

内容的提问来源于stack exchange,提问作者Code-Apprentice

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:30:59