当前位置: 代码网 > it编程>前端脚本>Python > 使用 OpenCV 实现五子棋检测

使用 OpenCV 实现五子棋检测

2024年07月31日 Python 我要评论
使用OpenCV实现定位棋子位置、识别棋子颜色以及五子联排检测


一、主要任务

1、定位棋子位置及识别棋子颜色
2、给出每个棋子的具体信息,包括行列信息以及颜色
3、检测所给棋盘是否出现五子联排


二、实现代码

# 导入相关库
import cv2
import numpy as np

# 读取图像
img = cv2.imread('board.png')
# cv2.imshow('img', img)

# 转换为灰度图像
gray = cv2.cvtcolor(img, cv2.color_bgr2gray)
# print('gray:', gray.shape)
# cv2.imshow('gray', gray)

# 高斯模糊
blur = cv2.gaussianblur(gray, (5, 5), 0)
# cv2.imshow('blur', blur)

# 边缘检测
edges = cv2.canny(blur, 50, 150)
# cv2.imshow('edges', edges)

# 轮廓提取
contours, hierarchy = cv2.findcontours(edges, cv2.retr_external, cv2.chain_approx_simple)

# 找到最大的轮廓,即棋盘的轮廓
max_area = 0
max_contour = none
for contour in contours:
    area = cv2.contourarea(contour)
    if area > max_area:
        max_area = area
        max_contour = contour

# 找到最小外接矩形,即棋盘的四个角点
rect = cv2.minarearect(max_contour)
box = cv2.boxpoints(rect)
box = np.intp(box)

# 绘制轮廓和角点
cv2.drawcontours(img, [box], 0, (0, 0, 255), 3)
for point in box:
    cv2.circle(img, tuple(point), 5, (0, 255, 0), -1)

width = int(rect[1][0])
height = int(rect[1][1])

warped = gray

# 圆检测,找到棋盘上的圆形,即棋子
circles = cv2.houghcircles(warped, method=cv2.hough_gradient,
                           dp=1, mindist=25, param1=100, param2=19,
                           minradius=10, maxradius=20)
print('circles: ', circles)
circles = np.uint16(np.around(circles))

# 计算每个圆形所在的格子位置
grid_size = width // 18 # 棋盘有19x19个格子
centers = [] # 存储圆心坐标和格子位置
for i in circles[0,:]:
    cx = i[0] # 圆心x坐标
    cy = i[1] # 圆心y坐标
    r = i[2] # 圆半径
    # 计算格子行号和列号,从0开始
    row = round(cy / grid_size) - 4
    col = round(cx / grid_size) - 4
    # 绘制圆形和圆心
    cv2.circle(img,(cx,cy),r,(0,255,0),2)
    cv2.circle(img,(cx,cy),2,(0,0,255),2)
    # 添加到列表中
    centers.append((cx,cy,row,col))

# 颜色空间转换,将图像转换为hsv空间
hsv = cv2.cvtcolor(img, cv2.color_bgr2hsv)

# 阈值分割,根据黑子和白子的颜色范围分别设置阈值,得到两个二值图像
lower_black = np.array([0, 0 ,10])
upper_black = np.array([180 ,255 ,90])
mask_black = cv2.inrange(hsv, lower_black, upper_black)
lower_white = np.array([0, 0 ,100])
upper_white = np.array([180 ,30 ,255])
mask_white = cv2.inrange(hsv, lower_white, upper_white)

# 与运算,将二值图像和原图像相与,得到黑子和白子的图像
res_black = cv2.bitwise_and(img, img, mask=mask_black)
res_white = cv2.bitwise_and(img, img, mask=mask_white)

res_black = cv2.cvtcolor(res_black, cv2.color_bgr2gray)
res_white = cv2.cvtcolor(res_white, cv2.color_bgr2gray)

# cv2.imshow('res_black', res_black)
# cv2.imshow('res_white', res_white)

# 统计每个圆形区域内的非零像素个数,判断是否有棋子,以及棋子的颜色
stones = [] # 存储棋子的颜色和位置
for center in centers:
    cx, cy, row, col = center
    # 在黑子图像上取一个圆形区域
    black_roi = res_black[cy-r:cy+r, cx-r:cx+r]
    # 计算非零像素个数
    nz_count_black = cv2.countnonzero(black_roi)
    # 如果大于阈值,则判断为黑子
    if nz_count_black > 50:
        color = 'black'
        stones.append((color, row, col))

        cv2.puttext(img, '(' + str(row+1) + ',' + str(col+1) + ')', (cx,cy), cv2.font_hershey_simplex, 0.4, (0, 0, 255), 1)

        continue
    # 在白子图像上取一个圆形区域
    white_roi = res_white[cy-r:cy+r, cx-r:cx+r]
    # 计算非零像素个数
    nz_count_white = cv2.countnonzero(white_roi)
    # 如果大于阈值,则判断为白子
    if nz_count_white > 50:
        color = 'white'
        stones.append((color, row, col))

        cv2.puttext(img, '(' + str(row+1) + ',' + str(col+1) + ')', (cx,cy), cv2.font_hershey_simplex, 0.4, (255, 0, 0), 1)

        continue

print('num: ', len(stones))

# 输出棋子的颜色和位置信息
board = []
for i in range(19):
    b = []
    for j in range(19):
        b.append(0)
    board.append(b)

cnt = 0
for stone in stones:
    color, row, col = stone
    print(f'there is a {color} stone at row {row+1} and column {col+1}.')
    board[row][col] = 1 if color == 'white' else 2

print(board)


def check_win(board, x, y):
    def check_dir(dx, dy):
        cnt = 1
        tx, ty = x + dx, y + dy
        while tx >= 0 and tx <= 18 and ty >= 0 and ty <= 18 and board[tx][ty] == board[x][y]:
            cnt += 1
            tx += dx
            ty += dy
        return cnt

    for dx, dy in [(0, 1), (1, 0), (1, 1), (1, -1)]:
        if check_dir(dx, dy) + check_dir(-dx, -dy) - 1 >= 5:
            return true
    return false

flag = false
for stone in stones:
    color, row, col = stone
    if check_win(board, row, col):
        print(f"{color} stone win!!! palce({row+1}, {col+1})")
        flag = true
        break

if not flag:
    print("no win")

# 如果需要扩展功能,可以在这里添加检测五子连排的代码

# 显示图像
cv2.imshow('img', img)
# cv2.imshow('warped', warped)
cv2.waitkey(0)
cv2.destroyallwindows()

部分代码来自网络

三、效果

(1)输入的棋盘

在这里插入图片描述

(2)输出的检测效果

在这里插入图片描述

(3)五子联排检测

在这里插入图片描述

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com