基于CNN的象棋棋子识别

数据集

数据集介绍

本篇博客采用的数据集是中国象棋棋子数据集,包含十种棋子分别是帅、仕、象、马、炮、车、兵、卒、将、相。
每个分好类的文件夹里有719张128x128像素的图片,形状一样,但是旋转角度不同。
数据来源,和鲸社区开放数据集,可以点击下面链接获取中国象棋棋子数据集(这个数据集里有数据集作者自己弄的识别结果,我在用的时候把这个.csv文件直接删除了。)
数据集截图如下:
在这里插入图片描述
在这里插入图片描述

数据预处理

单个图片读入程序是一个128*128的像素矩阵,矩阵的每个元素的值从0到255。当然了,这个数据集的图片分为两种,一种是仅含有0和255两种值——非黑即白,另一种就是上面看到的灰色的图片。因此,为了防止过拟合,我们需要将图片的像素矩阵进行标准化,标准化之后的矩阵如下:
在这里插入图片描述
至此,训练集的数据我们已经准备好了;但是,由于数据集中并不附带标签,所以我们需要自己生成标签,生成的标签如图:
在这里插入图片描述

卷积神经网络

什么是卷积神经网络

大部分书上对卷积神经网络的解释是:
卷积网络是指那些至少在网络的一层中使用卷积运算来代替一般的矩阵乘法运算的神经网络。
卷积网络对于处理网格状的数据例如图片有着天然的优势。
简单讲一下卷积神经网络用到的卷积运算是怎么的运算:
在这里插入图片描述
就像上图所展示的,卷积神经网络用到的卷积运算就是通过一个3*3的矩阵与矩阵上对应区域点积得到卷积后矩阵的一个值。当然了,上面的运算过程会使得矩阵丢失外面一圈数据,多次卷积后矩阵可能就无法进行运算了,所以一般我们会在卷积前给矩阵的最外圈添一圈零来避免这种事情的发生。
想要了解更加详细的过程,可以参考博客:卷积神经网络概念与原理

举个例子

接下来我们举个简单的卷积神经网络的例子吧,如下图:
在这里插入图片描述
这张图展示的是一张狗的图片进入卷积神经网络后,CNN是怎么对这张图进行识别的。狗的图片经历了卷积、池化、再卷积、再池化的过程,最后通过一个全连接层输出模型对图片的识别结果。

本篇博客用到的卷积神经网络模型

本篇博客用到的卷积神经网络比上面讲的稍微复杂点,结构如下图所示:
在这里插入图片描述
10层网络,相比于现今的深度神经网络来说当然不够看,但是对于象棋棋子的识别来说还是轻而易举的。
网络的搭建使用第三方库keras来实现(实在是因为tensorflow对于我来说有点难理解),具体的搭建过程可以参考博客:Keras搭建卷积神经网络

代码及结果展示

代码

别的不说,老规矩,上代码:

from PIL import Image
import numpy as np
from sklearn.preprocessing import StandardScaler
import sklearn
from sklearn.model_selection import train_test_split
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ReduceLROnPlateau
from keras.callbacks import ModelCheckpoint
from keras.callbacks import TensorBoard
from keras.models import load_model
import os
import warnings
# 忽略硬件加速的警告信息
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
warnings.filterwarnings('ignore')

#*********************************************************************************************************************************************#
scaler = StandardScaler()
path = "./象棋数据集"
dirs = os.listdir( path )
im2array = []
for file in dirs:
    pic_dir=os.path.join(path,file)  #子文件夹的路径
    for i in os.listdir(pic_dir):
        image_dir=os.path.join(pic_dir,i)  #子文件夹中图片的路径
        pic = np.array(Image.open(image_dir))
        im = scaler.fit_transform(pic)#标准化
        im2array.append(im)
im_array = np.array(im2array).reshape(7190,128,128,1)
#print(im_array.shape)
#*********************************************************************************************************************************************#
#生成标签
labels = np.zeros(shape=(7190,1),dtype=int)
for i in range(10):
    for j in range(719):
        labels[719*i+j][0] = i
#*********************************************************************************************************************************************#
#打乱数据集及数据标签
X,Y = sklearn.utils.shuffle(im_array,labels)
#print(Y[1:20])

X_train,X_test,y_train,y_test = train_test_split(X,Y,test_size=0.4,random_state=0)

#标签转换成独热编码
y_train = keras.utils.to_categorical(y_train, num_classes=10)
y_test = keras.utils.to_categorical(y_test, num_classes=10)
#print(X_train.shape)
#print(y_train.shape)

#batch_size=50    #每次喂给网络50组数据
#*********************************************************************************************************************************************#
#卷积神经网络模型,采用keras进行搭建
model = Sequential() #这里使用序贯模型,比较容易理解,序贯模型就像搭积木一样,将神经网络一层一层往上搭上去
#搭一个卷积层
model.add(Conv2D(32, (3, 3), activation='relu', padding='same', data_format='channels_last',name='layer1_con1',input_shape=(128, 128, 1)))
#再搭一层卷积层
model.add(Conv2D(32, (3, 3), activation='relu', padding='same', data_format='channels_last',name='layer1_con2'))
#搭一个最大池化层
model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2), padding = 'same', data_format='channels_last',name = 'layer1_pool'))
#dropout层可以防止过拟合,每次有25%的数据将被抛弃
model.add(Dropout(0.25))
#和上面的网络结构类似
model.add(Conv2D(64, (3, 3), activation='relu', padding='same', data_format='channels_last',name='layer2_con1'))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same', data_format='channels_last',name='layer2_con2'))
model.add(MaxPooling2D(pool_size=(2, 2),strides=(2,2), padding = 'same', data_format='channels_last',name = 'layer2_pool'))

model.add(Flatten())
model.add(Dense(128, activation='relu'))  #该全连接层共128个神经元
model.add(Dense(10, activation='softmax')) #一共分为10类,所以最后一层有10个神经元,并且采用softmax输出
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics = ['accuracy'])#定义损失值、优化器
#*********************************************************************************************************************************************#
#回调函数
learning_rate_reduction = ReduceLROnPlateau(monitor = 'val_acc', patience = 3,mode='auto',  verbose = 1, factor=0.5, min_lr = 0.00001)
#TensorBoard可视化
TensorBoard=TensorBoard(log_dir='./log', write_images=1, histogram_freq=1)

#训练
model.fit(X_train, y_train,epochs=3,callbacks=[learning_rate_reduction,TensorBoard])
#保存训练参数
#Checkpoint=ModelCheckpoint(filepath='./cnn_model',monitor='val_acc',mode='auto' ,save_best_only=True)
#计算得分
[loss,accuracy] = model.evaluate(X_test, y_test)
print('\nTest Loss: ', loss)
print('\nTest Accuracy: ', accuracy)
#保存模型
#model.save("model_new.h5")
#*********************************************************************************************************************************************#

从上到下,分别是数据预处理、生成标签、构建模型、训练并可视化、计算得分。

结果展示

我用的是vscode(我比较喜欢)来运行程序,最终结果如下图:
在这里插入图片描述
可以看到,经历三次迭代,训练集的准确度达到97%以上,测试集的准确率更是达到了99.5%,结果还是非常令人满意的。
可以访问该项目的GitHub地址基于CNN的象棋棋子识别(源码,数据集都在)。

猜你喜欢

转载自blog.csdn.net/qq_44725872/article/details/110286528