【基于深度学习的人机游戏机器人——视觉识别】

前言

本文是关于象棋机器人的识别码部分

一、鉴别方法

识别的方法一般包括目标检测、分类或者使用opencv处理图像。这三种方法我都有尝试,总的来说目标检测的精度需要大量的数据集作为支撑,分类任务所需的数据集较少,但是对棋盘的位置要求比较严格,opencv的图像处理方法不容易想到,也有一定的局限性。

1.目标检测

这里就不放代码了,也没什么好放的。毕竟都是网上的开源项目。只需键入用于训练的数据集。
但是局限性也特别明显,我一开始使用yolov3,后来换了其他的,但效果都不理想,因为一共32个棋子,拍摄下来都是小目标,想要一个不落地检测还是不太现实,特别是当时时间和精力有限的情况下。

2.分类

分类是先将每个可能包含棋子的区域进行划分,然后分别进行分类。棋盘处理部分代码如下:

import cv2 as cv
import os
from PIL import Image, ImageDraw, ImageFont
import numpy as np
from numpy import unicode

from classification import Classification

class chess(object):
    def __init__(self):

        self.a0 = [192, 393]
        self.a9 = [195, 104]
        self.i0 = [460, 396]

        self.parallel = {'a': '黑士', 'b': '黑象', 'c': '黑炮', 'empty': '空', 'k': '将', 'n': '黑马', 'p': '卒', 'r': '黑车',
                         'R_A': '红士', 'R_B': '红相', 'R_C': '红炮', 'R_K': '帅', 'R_N': '红马', 'R_P': '红兵', 'R_R': '红车'}
        self.parallel_en = {'a': 'a', 'b': 'b', 'c': 'c', 'empty': '0', 'k': 'k', 'n': 'n', 'p': 'p', 'r': 'r',
                            'R_A': 'A', 'R_B': 'B', 'R_C': 'C', 'R_K': 'K', 'R_N': 'N', 'R_P': 'P', 'R_R': 'R'}

    def getzb(self):
        a0 = self.a0
        a9 = self.a9
        i0 = self.i0
        x = []
        y = []
        w = (int(i0[0]) - int(a0[0])) / 8
        h = (int(i0[1]) - int(a0[1])) / 8
        width = (int(a0[0]) - int(a9[0])) / 9
        height = (int(a0[1]) - int(a9[1])) / 9
        # print(a0[0], type(a0[0]), width, type(width), a0[1], type(a0[1]), height, type(height))
        count_1 = 0
        count_2 = 0
        for i in range(90):
            x.append(int(int(a0[0]) + w * count_2 - width * count_1))
            y.append(int(int(a0[1]) + h * count_2 - height * count_1))
            # print("计算到:", i)
            if count_1 == 9:
                count_1 = 0
                count_2 += 1
            else:
                count_1 = count_1 + 1
        return x, y

    def puttxt(self, frame, zb, wenzi):
        img_PIL = Image.fromarray(cv.cvtColor(frame, cv.COLOR_BGR2RGB))  # 图像从OpenCV格式转换成PIL格式
        # font = ImageFont.truetype('ziti.ttf', 20)  # 40为字体大小,根据需要调整
        font = ImageFont.load_default().font
        fillColor = (255, 255, 0)
        draw = ImageDraw.Draw(img_PIL)
        draw.text(zb, wenzi, font=font, fill=fillColor)
        return cv.cvtColor(np.asarray(img_PIL[:, :, ::-1]), cv.COLOR_RGB2BGR)  # 转换回OpenCV格式

其实这就是最基本的分类任务,不过需要保证棋盘的位置固定,这样便可以根据棋盘的三个顶点(a0,a9,i0)位置,将棋盘分割为90个方格,棋子都是放置在这些方格中的,这样每张图片分为90个小尺寸图像的分类任务,执行起来速度也不慢,精度也有一定的保证,不过当时由于时间问题没有采用。
多加训练,实现这样的效果不难

3.Opencv图像处理

使用opencv是总体代码量和所需精力最少的,最难的是算法设计部分。
最终实现的步骤主要包括:使用行棋前拍摄的图像和行棋后拍摄的图像进行做差对比,计算得到变化后的坐标,也就是起点和终点的坐标(但还无法分辨哪个是起点哪个是终点),由于我们固定机械臂走黑棋,因此可以通过坐标中棋子的颜色判断起点与终点,这样便能够获得行棋信息更新棋局的FEN码。
代码显示如下:

def jiance(img1, img2, num=50, length=10):
    """
    :param img1:第一张图
    :param img2:第二张图
    :param num:设置白色像素的阈值
    :param length:设置先验框的一半边长
    :return:变化的坐标
    """
    print('识别中...')
    # red_1 = hongqi(img1)
    # red_2 = hongqi(img2)
    # if red_2 < red_1*hong:
    #     chizi = 1
    # else:
    #     chizi = 0
    a_org = img1
    b_org = img2
    a_gray = cv2.cvtColor(a_org, cv2.COLOR_BGR2GRAY)
    b_gray = cv2.cvtColor(b_org, cv2.COLOR_BGR2GRAY)
    before = cv2.subtract(a_gray, b_gray)  #
    ret, before = cv2.threshold(before, 50, 255, cv2.THRESH_BINARY)
    before_list = []
    dic_list = []
    old_qp = qipan.qipan()
    count = 0
    while True:
        count += 1
        # print('count', count)
        if count >= 40:
            print('识别失败,请重新走棋!!')
            return False
        for i in range(90):
            sum = 0
            sum_gray1 = 0
            sum_gray2 = 0
            zb = old_qp.qp[old_qp.qpd[i]][0]
            zb = eval(zb)
            x = zb[0]
            y = zb[1]
            x1 = x - length
            y1 = y - length
            x2 = x + length
            y2 = y + length
            for j in range(x1, x2):
                for k in range(y1, y2):
                    sum = sum + before[k][j]
            for j in range(x1-5, x2-5):
                for k in range(y1+5, y2+5):
                    sum_gray1 = sum_gray1 + a_gray[k][j]
                    sum_gray2 = sum_gray2 + b_gray[k][j]
            sub_gray = abs(sum_gray1 - sum_gray2)
            print('gray', sub_gray, sum_gray2)
            if sum > 255*num and sub_gray > 0.005*sum_gray2:
                before_list.append((x, y))
        if len(before_list) == 2:
            break
        elif len(before_list) > 2:
            num += 2
            before_list = []
        elif len(before_list) < 2:
            num -= 5
            before_list = []
        #cv2.circle(b_gray, (x, y), 30, 255)
        #cv2.imshow('b_gray', b_gray)
        #cv2.waitKey(0)
    # cv2.circle(before, before_list[0], 10, color=(255, 255, 255))
    # cv2.circle(before, before_list[1], 10, color=(255, 255, 255))
    # cv2.imshow('before', before)
    for (ok, op) in old_qp.qp.items():
        op = op[0].split(',')
        p = (int(op[0]), int(op[1]))
        if p in before_list:
            dic_list.append(ok)
    #print('dic_list:', dic_list)
    # cv2.waitKey(0)
    return dic_list

代码中还包含了判断阈值的自动迭代,提高了检测的鲁棒性。如果移动棋子时不小心碰到了其他棋子,或者后悔走棋重新下棋,也可以正确识别,但具体参数需要自己调整。 .

版权声明:本文为博主darkfan_cheese原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/weixin_44207288/article/details/123041431

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2022年2月22日 下午2:50
下一篇 2022年2月22日 下午3:10

相关推荐