--- tags: Coding --- # python CSGO自動瞄準 ## 介紹 此程式是為了輔助新手遊玩槍戰遊戲所開發。 :::info **用法:** 啟動程式後先點入遊戲裡面,進去遊戲裡過4秒後點擊一下滑鼠左鍵(為了抓去要截圖的位置),像是在圖一遊戲中點一下。程式就會自動判斷鼠標位置,並以鼠標中心往外延伸150px作為判斷區域。判斷區域像是圖二右上角。接著當遇到擊人時只需要點擊右鍵,準心就會自動移動到敵人身上。按p會關掉Ai偵測,按o可以開啟偵測。按下ESC鍵可以退出程式。 **圖一** ![prind](https://i.imgur.com/hejhVqt.jpg =250x142) **圖二** ![](https://i.imgur.com/PEUIC7y.png =250x155) ::: ## 程式碼 以下是程式碼,也可在我的github中找到 https://github.com/Bruce762/bodydetec-python/blob/main/bodydetect2.py 另外我有打包成exe檔放在雲端 可以在鏈結下載 https://drive.google.com/file/d/1bt4taPVGj9qmMW-y-2jNWaUSNeaGj84J/view?usp=sharing :::danger 以下**完整程式碼** ::: ```python= import cv2 from cv2 import FILLED import mediapipe as mp import numpy as np import mss import keyboard import time import win32api import win32con from pynput.mouse import Listener mpPose = mp.solutions.pose poses = mpPose.Pose(static_image_mode=True, model_complexity = 0, enable_segmentation = True, smooth_landmarks = False, min_detection_confidence=0.4) mpDraw = mp.solutions.drawing_utils poseLmsStyle = mpDraw.DrawingSpec(color=(0, 0, 255), thickness=10) poseconStyle = mpDraw.DrawingSpec(color=(0, 255, 0), thickness=10) sct = mss.mss()#mss截圖 click = False centerL = 0 centerT = 0 def clicked(x, y, button, is_press): if is_press: global click,centerL,centerT centerL=x centerT=y click=True listener = Listener(on_click=clicked) time.sleep(4) print("detection start") listener.start() while True: if click: listener.stop() print("successfully") break width = 300 height = 300 left = centerL - (width/2) top = centerT - (height/2) left = int(left) top = int(top) monitor = {"top": top, "left": left, "width": width, "height": height}#截圖方框位置 istart = True movespeed = 1 #Code of your program here while True: mouseleft = win32api.GetKeyState(0x02)#取得滑鼠右鍵,按下時值為-128 if(keyboard.is_pressed('o')): istart = True print("mode : open") if(keyboard.is_pressed('p')): istart = False print("mode : close") t=time.time() image = np.array(sct.grab(monitor))#截圖 imgHeigh = image.shape[0] imgWide = image.shape[1] if(istart): image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) results = poses.process(image) image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) if results.pose_landmarks: mpDraw.draw_landmarks(image, results.pose_landmarks, mpPose.POSE_CONNECTIONS, poseLmsStyle, poseconStyle) for i, lm in enumerate(results.pose_landmarks.landmark): if i == 11 and lm: leftlm = lm.x if i == 12 and lm: xPos = (lm.x+leftlm)*0.5* imgWide yPos = lm.y* imgHeigh xPos = int(xPos) yPos = int(yPos) image = cv2.circle(image, (xPos,yPos), 4, (255, 0, 0), FILLED) x=int(((lm.x+leftlm)*0.5-0.5)*imgWide*movespeed) y=int((lm.y-0.5)*imgHeigh*movespeed) if(mouseleft<0): win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, x, y, 0, 0) break image = cv2.resize(image,(0,0),fx=1,fy=1) cv2.putText(image,"Fps :"+str(int(1/(time.time()-t))),(1,30),cv2.FONT_HERSHEY_SIMPLEX,1,(204,255,0),2) cv2.imshow('MediaPipe Pose', image) if cv2.waitKey(1) & 0xFF == 27: break ``` ## 細節討論 ### 流程圖 使用draw.io完成 ![](https://i.imgur.com/zpEILjq.png) ### 滑鼠位置偵測 這段程式碼的功能是在偵測滑鼠的位置,當點一下左鍵後會傳回滑鼠位置當作程式偵測範圍。centerL與centerT分別是中心點的橫向與垂直座標,Listener(on_click=clicked) 負責回傳座標與滑鼠是否點擊。listener.start()開始偵測後while迴圈會重覆直到滑鼠左鍵被點擊,點擊後listener.stop()則會結束偵測,然後在centerL與centerT存下點擊時的座標。 ```python= from pynput.mouse import Listener click = False centerL = 0 centerT = 0 def clicked(x, y, button, is_press): if is_press: global click,centerL,centerT centerL=x centerT=y click=True listener = Listener(on_click=clicked) time.sleep(4) print("detection start") listener.start() while True: if click: listener.stop() print("successfully") break ``` ### 截圖 由於遊戲的畫面是由一幀接著一幀顯示螢幕上,所以我寫一個迴圈一直截圖,在一秒內多次截圖。而且會一直重複直到按下ESC鍵結束程式。截圖的部分經過我測試多組函示庫後,我發現mss函示庫最符合我的需求,其它像是pyautogui、win32api等函示庫不是截圖太慢就是操作時常失敗。由於在一秒之內可能需要盡可能截越多張圖,因此如果截圖耗費太多時間就會降低程式效率,原本偵測到的敵人可能就會跑走。 ```python= import mss import numpy as np sct = mss.mss()#mss截圖 while True: image = np.array(sct.grab(monitor))#截圖 主程式 if cv2.waitKey(1) & 0xFF == 27:#按下ESC break ``` ### Ai判斷函式庫 由於能力不足以自己訓練一個Ai,於是我想到竟然自己做不來就借助別人的。找了很久我找到Mediapipe,一個Google開源的函示庫。這是他們的官方 https://google.github.io/mediapipe/solutions/pose ,裡面有範例,我刪掉用不到的部分保留需要用到的。Mediapipe有很多函式可以用,而mp.soluiton.pose是其中有關人物偵測。第9行cv2.cvtColor()把圖片轉換成RGB的格式,因為需要RGB的格式Ai才能處理。第10行poses.process()把image(圖片)經過處理後,以NamedTuple的方式存在landmark,像是下圖(取自官方)總共有32個點。 ![](https://i.imgur.com/dbMomJk.png =400x230) 為了讓我們觀測到每個點的標示狀態,14行的mpDraw.draw_landmarks會在image上標出點與點之間的連線。poseLmsStyle決定圓點的顏色粗細,poseconStyle則是線。16行用enumerate幫每個點的landmark(NameTuple)編號。由於我設定瞄準的點是胸口,所以我取第11與第12個landmark裡面的x、y座標做平均。第31行把FPS偵數算出,方便我知道程式跑的速度。 ```python= import mediapipe as mp import numpy as np import cv2 import time mpPose = mp.solutions.pose poses = mpPose.Pose(static_image_mode=True, model_complexity = 0, enable_segmentation = True, smooth_landmarks = False, min_detection_confidence=0.4) mpDraw = mp.solutions.drawing_utils poseLmsStyle = mpDraw.DrawingSpec(color=(0, 0, 255), thickness=10) poseconStyle = mpDraw.DrawingSpec(color=(0, 255, 0), thickness=10) while True: t=time.time() image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) results = poses.process(image) image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) if results.pose_landmarks: mpDraw.draw_landmarks(image, results.pose_landmarks, mpPose.POSE_CONNECTIONS, poseLmsStyle, poseconStyle) for i, lm in enumerate(results.pose_landmarks.landmark): if i == 11 and lm: leftlm = lm.x if i == 12 and lm: xPos = (lm.x+leftlm)*0.5* imgWide yPos = lm.y* imgHeigh xPos = int(xPos) yPos = int(yPos) image = cv2.circle(image, (xPos,yPos), 4, (255, 0, 0), FILLED) x=int(((lm.x+leftlm)*0.5-0.5)*imgWide*movespeed) y=int((lm.y-0.5)*imgHeigh*movespeed) image = cv2.resize(image,(0,0),fx=1,fy=1) cv2.putText(image,"Fps :"+str(int(1/(time.time()-t))),(1,30),cv2.FONT_HERSHEY_SIMPLEX,1,(204,255,0),2) cv2.imshow('MediaPipe Pose', image) if cv2.waitKey(1) & 0xFF == 27: break ``` ### 瞄準偵測與移動 第4行我用win32api.GetKeyState()是取得滑鼠右鍵是否按壓,且按下時的值小於零。接著在14行只要判斷滑鼠右鍵被按下之後,就會用win32api.mouse_event()把滑鼠移動到指定的位置。第6行的keyboard.is_pressed('o')檢測鍵盤上的o有沒有備按下,我設定當按下時開起Ai偵測人的功能。而keyboard.is_pressed('p')就是當按下鍵盤p時關閉Ai偵測人的功能。 ```python= import keyboard import win32api import win32con mouseleft = win32api.GetKeyState(0x02)#取得滑鼠右鍵,按下時值為-128 if(keyboard.is_pressed('o')): istart = True print("mode : open") if(keyboard.is_pressed('p')): istart = False print("mode : close") if(mouseleft<0): win32api.mouse_event(win32con.MOUSEEVENTF_MOVE, x, y, 0, 0) ``` ## 參考網站 https://www.youtube.com/watch?v=1gZ-KaWjhGY&t=369s https://www.youtube.com/watch?v=brwgBf6VB0I https://google.github.io/mediapipe/solutions/pose https://www.youtube.com/watch?v=x4eeX7WJIuA&t=436s https://www.youtube.com/watch?v=xjrykYpaBBM&t=428s https://www.youtube.com/watch?v=zdMUJJKFdsU&t=2s https://www.twblogs.net/a/5d651e4cbd9eee5327fe6a58 https://stackoverflow.com/questions/68842206/python-mss-screen-capture-target-specific-windows https://stackoverflow.com/questions/61915912/how-can-i-make-the-cursor-move-in-game-using-python-ex-first-shooter-shooting 等等等多到數不清