这个项目的代码能够在个人Github上找到python
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数组中。算法
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
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()函数预处理后,只有帧的这一部分传递给模型进行预测。
整个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