当前位置: 首页 > news >正文

2024年TI杯E题-三子棋游戏装置方案分享-jdk123团队-第三弹视觉模块的封装

机械臂的设计

比赛第一天,我们打算做点提前量

视觉部分任务概述

赛题中,我们应该完成棋盘外棋子的识别,以及棋盘上棋子的识别。对此我们团队的方案为,先利用opencv,对九宫格棋盘进行识别
上图为仿真图
然后依据识别出九宫格的四个角点,来建立一个屏蔽罩,当识别内部棋子的时候,向外屏蔽,当识别外部棋子的时候,向内屏蔽。

内部棋子的识别

import time
import cv2
import numpy as np
import copydef main7(image_path):class BHSBFL:def __init__(self, image_path):# 读取图像并转换为灰度图self.image = cv2.imread(image_path)self.gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)def find_grid_coordinates(self):# 应用边缘检测edges = cv2.Canny(self.gray, 50, 150, apertureSize=3)# 使用霍夫变换检测直线lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=100, maxLineGap=10)# 复制原始图像以绘制检测结果(此处不再需要显示)image_copy = self.image.copy()# 寻找轮廓contours_info = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)contours = contours_info[0] if len(contours_info) == 2 else contours_info[1]if contours:# 选择最大的轮廓,这通常是九宫格的外框contour = max(contours, key=cv2.contourArea)# 获取最小的外接矩形rect = cv2.minAreaRect(contour)box = cv2.boxPoints(rect)box = np.int0(box)# 计算每个格子的中心并编号width, height = rect[1]cell_width = width / 3cell_height = height / 3# 确保顶点顺序为左上、右上、右下、左下box = sorted(box, key=lambda x: (x[1], x[0]))coordinates = []for i in range(3):for j in range(3):# 计算格子中心center_x = int(box[0][0] + j * cell_width + cell_width / 2)center_y = int(box[0][1] + i * cell_height + cell_height / 2)# 返回编号和中心坐标coordinates.append((i * 3 + j + 1, (center_x, center_y)))return coordinateselse:print("未找到轮廓")return []class ChessPieceDetector(BHSBFL):def __init__(self, image_path):super().__init__(image_path)self.image_path = image_path  # 存储图像路径self.coordinates = self.find_grid_coordinates()self.corner_coordinates = self.find_corners()self.image = cv2.imread(image_path)  # 读取图像def find_corners(self):gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)edged = cv2.Canny(gray, 30, 150)contours_info = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)contours = contours_info[0] if len(contours_info) == 2 else contours_info[1]if contours:largest_contour = max(contours, key=cv2.contourArea)rect = cv2.minAreaRect(largest_contour)box = cv2.boxPoints(rect)box = np.int0(box)return box.tolist()return []def detect_pieces(self):if not self.corner_coordinates:print("未找到九宫格角点坐标信息。")return []mask = np.zeros(self.gray.shape, dtype=np.uint8)cv2.fillPoly(mask, [np.array(self.corner_coordinates)], 255)masked_gray = cv2.bitwise_and(self.gray, self.gray, mask=mask)blurred = cv2.GaussianBlur(masked_gray, (9, 9), 2)circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=30, param1=50, param2=30,minRadius=10, maxRadius=95)piece_positions = []if circles is not None:circles = np.round(circles[0, :]).astype("int")# 为每个检测到的圆准备盒子和分数boxes = np.array([[x - r, y - r, x + r, y + r] for (x, y, r) in circles])scores = np.array([1] * len(circles))  # 这里简单设定每个圆的得分为1# 执行非极大抑制indices = cv2.dnn.NMSBoxes(boxes.tolist(), scores.tolist(), score_threshold=0.5, nms_threshold=0.5)# 解析经过非极大抑制后的圆if len(indices) > 0:for i in indices:i = i[0]  # 提取索引x, y, r = circles[i]# 获取颜色color = masked_gray[y, x]piece_color = "黑色" if color < 128 else "白色"closest_distance = float('inf')closest_number = Nonefor number, (cx, cy) in self.coordinates:distance = np.sqrt((x - cx) ** 2 + (y - cy) ** 2)if distance < closest_distance:closest_distance = distanceclosest_number = numberif closest_number is not None:piece_positions.append((closest_number, piece_color))# 标记棋子的位置point_color = (0, 0, 255) if piece_color == "黑色" else (0, 255, 0)  # 红色或绿色圆点cv2.circle(self.image, (x, y), 10, point_color, -1)piece_positions.sort(key=lambda x: x[0])return piece_positionsdef draw_corners(self):if self.corner_coordinates:for (x, y) in self.corner_coordinates:cv2.circle(self.image, (int(x), int(y)), 10, (0, 0, 255), -1)  # 红色圆点for i in range(4):cv2.line(self.image, tuple(self.corner_coordinates[i]), tuple(self.corner_coordinates[(i + 1) % 4]),(0, 255, 0), 2)cv2.imshow('Corners and Pieces', self.image)cv2.waitKey(0)cv2.destroyAllWindows()else:print("未能找到九宫格角点坐标信息。")def print_corners(self):if self.corner_coordinates:print("九宫格四个角的坐标信息:")for i, (x, y) in enumerate(self.corner_coordinates):print(f"角点 {i + 1}: (x: {x}, y: {y})")else:print("未能找到九宫格角点坐标信息。")detector = ChessPieceDetector(image_path)piece_positions = detector.detect_pieces()board = [[0 for _ in range(3)] for _ in range(3)]for number, color in piece_positions:row = (number - 1) // 3col = (number - 1) % 3if color == "黑色":board[row][col] = 1elif color == "白色":board[row][col] = -1print(f"棋子位置编号: {number}, 颜色: {color}")detector.print_corners()detector.draw_corners()print(board)return boardif __name__ == '__main__':main7('7plus.png')

在这里插入图片描述
棋子位置编号: 1, 颜色: 白色
棋子位置编号: 3, 颜色: 黑色
棋子位置编号: 5, 颜色: 黑色
九宫格四个角的坐标信息:
角点 1: (x: 1357, y: 958)
角点 2: (x: 612, y: 958)
角点 3: (x: 612, y: 215)
角点 4: (x: 1357, y: 215)

外部棋子的识别

import cv2
import numpy as np
from bhde import BHSBFL  # 导入 BHSBFL 类class ChessPieceDetector(BHSBFL):def __init__(self, image_path):super().__init__(image_path)self.image_path = image_path  # 存储图像路径self.coordinates = self.find_grid_coordinates()self.corner_coordinates = self.find_corners()self.image = cv2.imread(image_path)  # 读取图像self.masked_image = self.image.copy()  # 复制图像用于处理def find_corners(self):# 将图像转换为灰度图像gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)# 应用边缘检测edged = cv2.Canny(gray, 30, 150)# 查找轮廓_,contours, _ = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)if contours:# 选择最大轮廓largest_contour = max(contours, key=cv2.contourArea)# 获取轮廓的最小外接矩形rect = cv2.minAreaRect(largest_contour)box = cv2.boxPoints(rect)box = np.int0(box)  # 转换为整数return box.tolist()  # 返回四个角点坐标return []def mask_rectangle(self):if self.corner_coordinates:# 创建一个全黑的遮罩,尺寸与图像相同mask = np.zeros(self.image.shape[:2], dtype=np.uint8)# 将角点坐标转换为 NumPy 数组points = np.array(self.corner_coordinates, dtype=np.int32)# 填充多边形区域cv2.fillPoly(mask, [points], 255)  # 填充为白色(255)# 使用 bitwise_not 反转遮罩mask_inv = cv2.bitwise_not(mask)# 将遮罩应用到图像上self.masked_image = cv2.bitwise_and(self.image, self.image, mask=mask_inv)else:print("未能找到九宫格角点坐标信息。")def detect_pieces(self):# 高斯模糊blurred = cv2.GaussianBlur(cv2.cvtColor(self.masked_image, cv2.COLOR_BGR2GRAY), (9, 9), 2)# 霍夫圆变换检测圆dp = cv2.getTrackbarPos('dp', 'Adjustments') / 10minDist = cv2.getTrackbarPos('minDist', 'Adjustments')param1 = cv2.getTrackbarPos('param1', 'Adjustments')param2 = cv2.getTrackbarPos('param2', 'Adjustments')minRadius = cv2.getTrackbarPos('minRadius', 'Adjustments')maxRadius = cv2.getTrackbarPos('maxRadius', 'Adjustments')circles = cv2.HoughCircles(blurred, cv2.HOUGH_GRADIENT, dp=dp, minDist=minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)# 存储棋子位置piece_positions = []if circles is not None:circles = np.round(circles[0, :]).astype("int")# 非极大抑制boxes = np.array([[x - r, y - r, x + r, y + r] for x, y, r in circles])scores = np.array([r for x, y, r in circles])indices = cv2.dnn.NMSBoxes(boxes.tolist(), scores.tolist(), score_threshold=0, nms_threshold=0.5)for i in indices:x, y, r = circles[i[0]]# 提取圆区域的颜色(使用中点的灰度值)color = cv2.cvtColor(self.masked_image, cv2.COLOR_BGR2GRAY)[y, x]# 判断是黑色棋子还是白色棋子(假设黑色棋子颜色较深,白色棋子颜色较浅)piece_color = "黑色" if color < 128 else "白色"# 存储棋子的位置和颜色piece_positions.append(((x, y), piece_color))# 按照 y 坐标从下到上排序piece_positions.sort(key=lambda pos: (pos[0][1], pos[0][0]))return piece_positionsdef draw_pieces(self):if self.corner_coordinates:# 绘制矩形角点for (x, y) in self.corner_coordinates:cv2.circle(self.image, (int(x), int(y)), 10, (0, 0, 255), -1)  # 红色圆点# 绘制角点之间的线for i in range(4):cv2.line(self.image, tuple(self.corner_coordinates[i]), tuple(self.corner_coordinates[(i + 1) % 4]),(0, 255, 0), 2)  # 绿色线条# 分开标号黑白棋子,并按从下往上的顺序编号piece_positions = self.detect_pieces()black_counter = 1white_counter = 1for (x, y), color in piece_positions:if color == "黑色":cv2.circle(self.image, (x, y), 10, (255, 0, 0), -1)  # 蓝色圆点text_color = (255, 255, 255)  # 白色文本cv2.putText(self.image, str(black_counter), (x - 10, y + 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 1, cv2.LINE_AA)black_counter += 1else:cv2.circle(self.image, (x, y), 10, (128, 0, 128), -1)  # 紫色圆点text_color = (255, 255, 255)  # 白色文本cv2.putText(self.image, str(white_counter), (x - 10, y + 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 1, cv2.LINE_AA)white_counter += 1# 显示图像cv2.imshow('Detected Pieces', self.image)cv2.waitKey(0)cv2.destroyAllWindows()# 保存绘制好的图像到文件cv2.imwrite(output_path, self.image)print(f"检测结果已保存到 {output_path}")cv2.waitKey(0)cv2.destroyAllWindows()def print_corners(self):if self.corner_coordinates:print("九宫格四个角的坐标信息:")for i, (x, y) in enumerate(self.corner_coordinates):print(f"角点 {i + 1}: (x: {x}, y: {y})")else:print("未能找到九宫格角点坐标信息。")def update(x):# 更新回调函数detector.draw_pieces()# 使用示例
if __name__ == "__main__":detector = ChessPieceDetector('22.jpg')detector.mask_rectangle()  # 屏蔽九宫格区域detector.print_corners()  # 打印九宫格四个角的坐标信息# 创建调整窗口cv2.namedWindow('Adjustments')# 创建滑动条cv2.createTrackbar('dp', 'Adjustments', 12, 20, update)cv2.createTrackbar('minDist', 'Adjustments', 30, 100, update)cv2.createTrackbar('param1', 'Adjustments', 50, 200, update)cv2.createTrackbar('param2', 'Adjustments', 30, 100, update)cv2.createTrackbar('minRadius', 'Adjustments', 10, 100, update)cv2.createTrackbar('maxRadius', 'Adjustments', 89, 100, update)detector.draw_pieces()  # 初始绘制cv2.waitKey(0)cv2.destroyAllWindows()

在这里插入图片描述
值得一提的是,由于仿真与实际的不同,特意在代码里面加入了调节阈值的窗口。
并且,由于算法的缺陷性,起初在检测的时候,棋子的中央会出现多个识别点。
这里我们团队创新性的引用了YOLOV5中的非极大值抑制(Non-Maximum Suppression)NMS算法。过滤掉不必要的边框。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 打造核心竞争力:中集集团技术创新之路
  • 【MetaGPT系列】【MetaGPT完全实践宝典——多智能体实践(辩论赛)构建】
  • 十九、虚拟机VMware Workstation(CentOSDebian)的安装
  • 前端项目中的Server-sent Events(SSE)项目实践及其与websocket的区别
  • PDF怎么在线转Word?介绍四种转换方案
  • MATLAB(R和C++)大肠杆菌合成生物机械数学模型
  • c语言中的volatile(从系统层面看)
  • 计算机网络408考研 2019
  • python:“ func“和“ func()“的区别
  • 用Python打造精彩动画与视频,9.3 项目案例分享与反思
  • 寻参算法之狼群算法
  • k8s持久化存储PV和PVC
  • 【JVM篇】自动内存管理——HotSpot虚拟机对象探秘
  • 【zlm】针对单个设备的音频的编码的设置
  • 【通用的Python爬虫示例】
  • [译] 怎样写一个基础的编译器
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • canvas绘制圆角头像
  • CSS实用技巧
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • js中的正则表达式入门
  • k8s 面向应用开发者的基础命令
  • PaddlePaddle-GitHub的正确打开姿势
  • quasar-framework cnodejs社区
  • Vue.js 移动端适配之 vw 解决方案
  • Vue官网教程学习过程中值得记录的一些事情
  • 阿里研究院入选中国企业智库系统影响力榜
  • 番外篇1:在Windows环境下安装JDK
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 微信小程序实战练习(仿五洲到家微信版)
  • 译米田引理
  • 字符串匹配基础上
  • Python 之网络式编程
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • #14vue3生成表单并跳转到外部地址的方式
  • #HarmonyOS:基础语法
  • #图像处理
  • $.ajax()
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (2024.6.23)最新版MAVEN的安装和配置教程(超详细)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (第二周)效能测试
  • (独孤九剑)--文件系统
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (三)SvelteKit教程:layout 文件
  • (转)ORM
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .net8.0与halcon编程环境构建
  • .NET大文件上传知识整理
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .NET企业级应用架构设计系列之结尾篇
  • .NET企业级应用架构设计系列之应用服务器