這個項目的代碼能夠在個人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