我已经使用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
)
关键点 :由于我们的图片尺寸为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规则和得分。所以我们开始加载我们训练过的模型,它在开始程序的预测部分之前显示倒计时,预测后,分数会根据球员的动作进行更新。
我们使用cv2.rectangle()显式地绘制目标区域,使用prepImg()函数预处理后,只有帧的这一部分传递给模型进行预测。
结论:我们已经成功地实现并学习了这个项目的工作原理,所以请继续使用我的实现进行其它实验学习。我做的一个主要的改进可能是增加了手部检测,所以我们不需要显式地绘制目标区域,模型将首先检测手部位置,然后进行预测。我鼓励你改进这个项目,并给我你的建议。精益求精!