使用 OpenCV 实现五子棋检测

该代码示例展示了如何利用OpenCV库处理图像,实现对围棋棋盘上棋子的位置、颜色的识别,并检测是否存在五子连排的情况。首先,通过图像预处理步骤如灰度转换、边缘检测和轮廓提取找到棋盘轮廓。接着,使用HoughCircles检测棋子并计算其在棋盘上的位置。然后,通过颜色空间转换和阈值分割区分黑子和白子。最后,检查是否有五子连排的棋局。
摘要由CSDN通过智能技术生成


一、主要任务

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)五子联排检测

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值