从棋盘识别到AI裁判:手把手教你用OpenCV搭建五子棋对弈记录系统 从棋盘识别到AI裁判手把手教你用OpenCV搭建五子棋对弈记录系统线下五子棋比赛中裁判需要全程紧盯棋盘记录每一步落子位置这不仅耗费人力还容易因疲劳导致误判。传统的人工记录方式已经无法满足现代棋类赛事对效率和准确性的双重需求。本文将带你从零开始构建一套完整的五子棋对弈记录系统这套系统能够自动识别棋盘状态、记录棋谱、判断胜负甚至提供棋局复盘功能。1. 系统架构设计一套完整的五子棋对弈记录系统需要包含以下几个核心模块图像采集模块负责定时拍摄棋盘图像棋盘识别模块定位棋盘位置并校正透视变形棋子检测模块识别每个棋子的位置和颜色棋局分析模块判断当前棋局状态和胜负数据存储模块将棋局信息序列化为标准棋谱格式可视化模块提供棋局回放和分析功能1.1 硬件选型建议对于线下比赛场景我们需要考虑以下硬件因素设备类型推荐配置注意事项摄像头1080P及以上分辨率固定安装位置确保棋盘完整入镜照明均匀柔和的LED光源避免反光和阴影干扰棋盘标准19×19棋盘建议使用高对比度棋盘提示在实际部署时建议将摄像头固定在棋盘正上方约1.5米处确保棋盘占据画面主要区域。2. 核心算法实现2.1 棋盘定位与校正棋盘定位是整个系统的基础我们需要准确找到棋盘在图像中的位置并校正透视变形def find_chessboard(image): # 转换为灰度图 gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 高斯模糊降噪 blur cv2.GaussianBlur(gray, (5, 5), 0) # 边缘检测 edges cv2.Canny(blur, 50, 150) # 查找轮廓 contours, _ cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 找到面积最大的轮廓棋盘 max_contour max(contours, keycv2.contourArea) # 获取最小外接矩形 rect cv2.minAreaRect(max_contour) box cv2.boxPoints(rect) box np.intp(box) # 透视变换校正 width, height int(rect[1][0]), int(rect[1][1]) dst_pts np.array([[0, 0], [width-1, 0], [width-1, height-1], [0, height-1]], dtypefloat32) M cv2.getPerspectiveTransform(box.astype(float32), dst_pts) warped cv2.warpPerspective(image, M, (width, height)) return warped, M2.2 棋子检测与识别棋子检测需要解决三个关键问题准确定位每个棋子的中心位置正确识别棋子颜色黑/白将棋子位置映射到棋盘坐标def detect_stones(image): # 转换为HSV颜色空间 hsv cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 定义黑白棋子的颜色范围 lower_black np.array([0, 0, 10]) upper_black np.array([180, 255, 90]) lower_white np.array([0, 0, 100]) upper_white np.array([180, 30, 255]) # 创建颜色掩膜 mask_black cv2.inRange(hsv, lower_black, upper_black) mask_white cv2.inRange(hsv, lower_white, upper_white) # 霍夫圆检测 gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) circles cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp1, minDist25, param1100, param219, minRadius10, maxRadius20) stones [] if circles is not None: circles np.uint16(np.around(circles[0])) for (x, y, r) in circles: # 计算棋盘坐标 row round(y / (image.shape[0] / 19)) col round(x / (image.shape[1] / 19)) # 判断棋子颜色 black_area mask_black[y-r:yr, x-r:xr] white_area mask_white[y-r:yr, x-r:xr] if cv2.countNonZero(black_area) 50: stones.append((black, row, col)) elif cv2.countNonZero(white_area) 50: stones.append((white, row, col)) return stones3. 胜负判断算法五子棋的胜负判断需要检查四个方向水平、垂直、两个对角线是否有连续五个同色棋子def check_win(board, last_move): directions [(0, 1), (1, 0), (1, 1), (1, -1)] color, row, col last_move for dx, dy in directions: count 1 # 正向检查 x, y row dx, col dy while 0 x 19 and 0 y 19 and board[x][y] color: count 1 x dx y dy # 反向检查 x, y row - dx, col - dy while 0 x 19 and 0 y 19 and board[x][y] color: count 1 x - dx y - dy if count 5: return True return False4. 工程化挑战与解决方案在实际部署中我们会遇到各种边缘情况和性能挑战4.1 处理棋子遮挡问题在比赛过程中选手的手可能会遮挡部分棋子。我们可以采用以下策略多帧验证连续分析多帧图像只有当棋子被检测到多次才确认运动检测识别选手手的移动在选手手离开后立即拍摄新图像历史数据参考基于之前的棋盘状态推断可能的落子位置4.2 提高实时性为了确保系统能够实时响应需要进行以下优化区域检测只检测棋盘区域而非整张图像增量更新只检查可能发生变化的区域如新落子位置附近并行处理将图像采集与处理分离到不同线程4.3 棋谱存储与标准化为了便于棋局分析和分享我们需要将棋局信息存储为标准格式如SGFdef save_to_sgf(moves, filename): with open(filename, w) as f: f.write((;GM[1]FF[4]CA[UTF-8]AP[GomokuRecorder]SZ[19]\n) for i, (color, row, col) in enumerate(moves): x chr(ord(a) col) y chr(ord(a) row) f.write(f;{B if color black else W}[{x}{y}]\n) f.write())5. 系统集成与部署将各个模块整合为一个完整的系统需要考虑以下方面用户界面提供简单的控制界面让裁判可以开始/结束记录异常处理当检测到异常情况如棋盘被遮挡时发出警报数据备份定期自动备份棋谱数据性能监控监控系统资源使用情况确保稳定运行在实际部署中我们发现以下几个配置参数对系统性能影响最大参数推荐值调整建议图像分辨率1920x1080过低影响识别精度过高增加处理负担检测间隔2秒根据比赛节奏调整霍夫圆检测参数215-25影响棋子检测灵敏度颜色阈值需现场校准根据光照条件调整注意系统部署后需要进行现场校准特别是颜色识别阈值和棋盘定位参数以确保在不同光照条件下的稳定性。