使用Tensorflow+OpenCV构建会玩石头剪刀布的AI

使用Tensorflow+OpenCV构建会玩石头剪刀布的AI

这个项目的代码能够在个人Github上找到python

  • https://github.com/HOD101s/RockPaperScissor-AI-
    简介
    这个项目的基础是深度学习和图像分类,目的是建立一个简单而有趣的石头剪刀布游戏。首先,这个项目是我在5月份的COVID19隔离期中无聊的产物,但愿当你读到这个时,一切都恢复正常了。个人目的是经过这篇文章用简单的术语向初学者解释这个项目的基本原理。让咱们开始吧!
    在构建任何类型的深度学习应用程序时,有三个主要步骤:
  • 收集和处理数据
  • 创建一个合适的人工智能模型
  • 部署使用
    整个项目都引用了个人Github repo,并与之携手并进,因此请作好参考准备。
    项目地址:https://github.com/HOD101s/RockPaperScissor-AI-
    收集咱们的数据
    使用Tensorflow+OpenCV构建会玩石头剪刀布的AI
    任何深度学习模型的基础都是数据,任何一位机器学习工程师都会赞成这一点,在ML中,数据远比算法自己重要。咱们须要收集石头,布和剪刀的符号图像,我没有下载别人的数据并在上面进行训练,而是制做了本身的数据集,鼓励你也创建本身的数据集。以后尝试更改数据并从新训练模型,以查看数据对深度学习模型究竟有怎样的影响。
PATH = os.getcwd()+'\\'
cap = cv2.VideoCapture(0)

label = sys.argv[1]

SAVE_PATH = os.path.join(PATH, label)

try:
    os.mkdir(SAVE_PATH)
except FileExistsError:
    pass

ct = int(sys.argv[2])
maxCt = int(sys.argv[3])+1
print("Hit Space to Capture Image")

while True:
    ret, frame = cap.read()
    cv2.imshow('Get Data : '+label,frame[50:350,100:450])
    if cv2.waitKey(1) & 0xFF == ord(' '):
        cv2.imwrite(SAVE_PATH+'\\'+label+'{}.jpg'.format(ct),frame[50:350,100:450])
        print(SAVE_PATH+'\\'+label+'{}.jpg Captured'.format(ct))
        ct+=1
    if ct >= maxCt:
        break

cap.release()
cv2.destroyAllWindows()

我使用了Python的OpenCV库进行全部与相机相关的操做,因此这里的label指的是图像属于哪一个类,根据标签,图像保存在适当的目录中。ct和maxCt是用来保存图像的起始索引和最终索引,剩下的是标准的OpenCV代码,用于获取网络摄像头源并将图像保存到目录中。须要注意的一点是,我全部的图片维数都是300 x 300的。运行此目录树后,个人目录树以下所示。git

C:.
├───paper
    │ paper0.jpg
    │ paper1.jpg
    │ paper2.jpg
│
├───rock
    │ rock0.jpg
    │ rock1.jpg
    │ rock2.jpg
│
└───scissor
     scissor0.jpg
     scissor1.jpg
     scissor2.jpg

若是你引用的是Github存储库(https://github.com/HOD101s/RockPaperScissor-AI-) ,则getData.py会为你完成这项工做!
预处理咱们的数据
咱们须要使用图像,而计算机能够识别数字,所以,咱们将全部图像转换为它们各自的矢量表示,另外,咱们的标签尚待生成,因为已创建的标签不能是文本,所以我使用shape_to_label字典为每一个类手动构建了“独热编码”表示。github

DATA_PATH = sys.argv[1] # Path to folder containing data

shape_to_label = {'rock':np.array([1.,0.,0.,0.]),'paper':np.array([0.,1.,0.,0.]),'scissor':np.array([0.,0.,1.,0.]),'ok':np.array([0.,0.,0.,1.])}
arr_to_shape = {np.argmax(shape_to_label[x]):x for x in shape_to_label.keys()}

imgData = list()
labels = list()

for dr in os.listdir(DATA_PATH):
    if dr not in ['rock','paper','scissor']:
        continue
    print(dr)
    lb = shape_to_label[dr]
    i = 0
    for pic in os.listdir(os.path.join(DATA_PATH,dr)):
        path = os.path.join(DATA_PATH,dr+'/'+pic)
        img = cv2.imread(path)
        imgData.append([img,lb])
        imgData.append([cv2.flip(img, 1),lb]) #horizontally flipped image
        imgData.append([cv2.resize(img[50:250,50:250],(300,300)),lb]) # zoom : crop in and resize
        i+=3
    print(i)

np.random.shuffle(imgData)

imgData,labels = zip(*imgData)

imgData = np.array(imgData)
labels = np.array(labels)

当咱们根据类将图像保存在目录中时,目录名用做标签,该标签使用shape_to_label字典转换为独热表示。在咱们遍历系统中的文件以访问图像以后,cv2.imread()函数返回图像的矢量表示。
咱们经过翻转图像并放大图像来进行一些手动的数据加强,这增长了咱们的数据集大小,而无需拍摄新照片,数据加强是生成数据集的关键部分。最后,图像和标签存储在单独的numpy数组中。算法

  • cv2.imread()函数
    https://www.geeksforgeeks.org/python-opencv-cv2-imread-method/
  • 更多关于数据加强的信息。
    https://towardsdatascience.com/data-augmentation-for-deep-learning-4fe21d1a4eb9
    经过迁移学习创建咱们的模型:
    在处理图像数据时,有许多通过预训练的模型可供使用,这些模型已经在具备数千个标签的数据集上进行了训练,因为这些模型经过其应用程序api的Tensorflow和Keras分布,咱们可使用这些模型,这使得在咱们的应用程序中包含这些预先训练的模型看起来很容易!
    使用Tensorflow+OpenCV构建会玩石头剪刀布的AI
    总之,迁移学习采用的是通过预训练的模型,而且不包含进行最终预测的最终层,可以区分这种状况下图像中的特征,并将这些信息传递给咱们本身的Dense神经网络。
    为何不训练你本身的模型呢?彻底取决于你!然而,使用迁移学习能够在不少时候使你的进步更快,从某种意义上说,你避免了重复造轮子。
    其余一些受欢迎的预训练模型:
  • InceptionV3
  • VGG16/19
  • ResNet
  • MobileNet
    这是一篇关于迁移学习的有趣文章!
  • https://ruder.io/transfer-learning/
    注:每当咱们处理图像数据时,几乎都会使用卷积神经层,这里使用的迁移学习模型就有这些层。有关CNNs的更多信息,请访问:
  • https://medium.com/@RaghavPrabhu/understanding-of-convolutional-neural-network-cnn-deep-learning-99760835f148
    实现
    使用Tensorflow+OpenCV构建会玩石头剪刀布的AI
    我已经使用DenseNet121模型进行特征提取,其输出最终将输入到我本身的Dense神经网络中。
densenet = DenseNet121(include_top=False, weights='imagenet', classes=3,input_shape=(300,300,3))
densenet.trainable=True

def genericModel(base):
    model = Sequential()
    model.add(base)
    model.add(MaxPool2D())
    model.add(Flatten())
    model.add(Dense(3,activation='softmax'))
    model.compile(optimizer=Adam(),loss='categorical_crossentropy',metrics=['acc'])
    return model

dnet = genericModel(densenet)

history = dnet.fit(
    x=imgData,
    y=labels,
    batch_size = 16,
    epochs=8,
    callbacks=[checkpoint,es],
    validation_split=0.2
)

关键点 :json

  • 因为咱们的图片尺寸为300x300,所以指定的输入形状也为3x300x300,3表明RGB的维度信息,所以该层具备足够的神经元来处理整个图像。
  • 咱们将DenseNet层用做第一层,而后使用咱们本身的Dense神经网络。
  • 我已将可训练参数设置为True,这也会从新训练DenseNet的权重。尽管花了不少时间,可是这给了我更好的结果。我建议你在本身的实现中尝试经过更改此类参数(也称为超参数)来尝试不一样的迭代。
  • 因为咱们有3类Rock-Paper-Scissor,最后一层是具备3个神经元和softmax激活的全链接层。
  • 最后一层返回图像属于3类中特定类的几率。
  • 若是你引用的是GitHub repo(https://github.com/HOD101s/RockPaperScissor-AI-) 的train.py,则要注意数据准备和模型训练!
    至此,咱们已经收集了数据,创建并训练了模型,剩下的部分是使用OpenCV进行部署
    OpenCV实现:
    此实现的流程很简单:
  • 启动网络摄像头并读取每一个帧
  • 将此框架传递给模型进行分类,即预测类
  • 用电脑随意移动
  • 计算分数
def prepImg(pth):
    return cv2.resize(pth,(300,300)).reshape(1,300,300,3)

with open('model.json', 'r') as f:
    loaded_model_json = f.read()
loaded_model = model_from_json(loaded_model_json)
loaded_model.load_weights("modelweights.h5")
print("Loaded model from disk")

for rounds in range(NUM_ROUNDS):
    pred = ""
    for i in range(90):
        ret,frame = cap.read()

        # Countdown    
        if i//20 < 3 :
            frame = cv2.putText(frame,str(i//20+1),(320,100),cv2.FONT_HERSHEY_SIMPLEX,3,(250,250,0),2,cv2.LINE_AA)

        # Prediction
        elif i/20 < 3.5:
            pred = arr_to_shape[np.argmax(loaded_model.predict(prepImg(frame[50:350,100:400])))]

        # Get Bots Move
        elif i/20 == 3.5:
            bplay = random.choice(options)            
            print(pred,bplay)

        # Update Score
        elif i//20 == 4:
            playerScore,botScore = updateScore(pred,bplay,playerScore,botScore)
            break

        cv2.rectangle(frame, (100, 150), (300, 350), (255, 255, 255), 2)
        frame = cv2.putText(frame,"Player : {}      Bot : {}".format(playerScore,botScore),(120,400),cv2.FONT_HERSHEY_SIMPLEX,1,(250,250,0),2,cv2.LINE_AA)
        frame = cv2.putText(frame,pred,(150,140),cv2.FONT_HERSHEY_SIMPLEX,1,(250,250,0),2,cv2.LINE_AA)
        frame = cv2.putText(frame,"Bot Played : {}".format(bplay),(300,140),cv2.FONT_HERSHEY_SIMPLEX,1,(250,250,0),2,cv2.LINE_AA)        
        cv2.imshow('Rock Paper Scissor',frame)
        if cv2.waitKey(1) & 0xff == ord('q'):
            break

上面的代码片断包含至关重要的代码块,其他部分只是使游戏易于使用,RPS规则和得分。
因此咱们开始加载咱们训练过的模型,它在开始程序的预测部分以前显示倒计时,预测后,分数会根据球员的动做进行更新。
使用Tensorflow+OpenCV构建会玩石头剪刀布的AI
咱们使用cv2.rectangle()显式地绘制目标区域,使用prepImg()函数预处理后,只有帧的这一部分传递给模型进行预测。
整个play.py在个人repo上有代码(https://github.com/HOD101s/RockPaperScissor-AI-/blob/master/play.py)。
结论:
咱们已经成功地实现并学习了这个项目的工做原理,因此请继续使用个人实现进行其它实验学习。我作的一个主要的改进多是增长了手部检测,因此咱们不须要显式地绘制目标区域,模型将首先检测手部位置,而后进行预测。我鼓励你改进这个项目,并给我你的建议。精益求精!
原文连接:https://towardsdatascience.com/building-a-rock-paper-scissors-ai-using-tensorflow-and-opencv-d5fc44fc8222api

相关文章
相关标签/搜索