├── README.md ├── demo.py └── image.png /README.md: -------------------------------------------------------------------------------- 1 | # python-opencv_block 2 | 基于opencv和多线程的别踩白块儿游戏辅助 3 | 运行时需点击窗口,左上和右下,确定游戏框方位 4 | bibli教学地址 5 | https://www.bilibili.com/video/BV1N5411w7ab 6 | -------------------------------------------------------------------------------- /demo.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from matplotlib import pyplot as plt 4 | # import win32api,win32con 5 | from win32api import GetSystemMetrics 6 | from win32con import SRCCOPY,SM_CXSCREEN,SM_CYSCREEN 7 | from win32gui import FindWindow, GetWindowDC, DeleteObject, ReleaseDC,GetDesktopWindow 8 | from win32ui import CreateDCFromHandle, CreateBitmap 9 | import time 10 | import pyautogui 11 | import sys 12 | import threading 13 | 14 | 15 | # 左上和右上坐标 16 | 17 | class GameStart(): 18 | 19 | # 点击屏幕并且获取坐标 20 | def __init__(self): 21 | self.first_pointX=0 22 | self.first_pointY=0 23 | self.second_pointX=0 24 | self.second_pointY=0 25 | self.clock_number=0 26 | self.center_post_list=[] 27 | def on_EVENT_LBUTTONDOWN(self,event, x, y, flags, param): 28 | if (self.clock_number > 1): 29 | cv2.destroyWindow('image') 30 | # 左键按下 31 | if event == cv2.EVENT_LBUTTONDOWN: 32 | # 输出坐标信息 33 | 34 | xy = "%d,%d" % (x, y) 35 | print(xy) 36 | if(self.clock_number==0): 37 | self.first_pointX=x 38 | self.first_pointY=y 39 | elif(self.clock_number==1): 40 | self.second_pointX = x 41 | self.second_pointY = y 42 | self.clock_number+=1 43 | def windowshots(self,x1, y1, x2, y2): 44 | w, h = x2 - x1, y2 - y1 45 | # wDC = GetDC(hwnd) 46 | # 根据窗口句柄获取窗口的设备上下文DC(Divice Context) 47 | # 获取桌面 48 | hdesktop = GetDesktopWindow() 49 | wDC = GetWindowDC(hdesktop) 50 | # 根据窗口的DC获取dcObj 51 | dcObj = CreateDCFromHandle(wDC) 52 | # dcObj创建可兼容的DC 53 | cDC = dcObj.CreateCompatibleDC() 54 | # 创建bigmap准备保存图片 55 | dataBitMap = CreateBitmap() 56 | # 为bitmap开辟空间 57 | dataBitMap.CreateCompatibleBitmap(dcObj, w, h) 58 | # 高度cDC,将截图保存到dataBitMap中 59 | cDC.SelectObject(dataBitMap) 60 | # 截取从左上角(0,0)长宽为(w,h)的图片 61 | cDC.BitBlt((0, 0), (w, h), dcObj, (x1, y1), SRCCOPY) 62 | # 保存图像 63 | # dataBitMap.SaveBitmapFile(cDC, 'test.jpg') 64 | signedIntsArray = dataBitMap.GetBitmapBits(True) 65 | # Free Resources 66 | # 释放资源 67 | DeleteObject(dataBitMap.GetHandle()) 68 | cDC.DeleteDC() 69 | dcObj.DeleteDC() 70 | ReleaseDC(hdesktop, wDC) 71 | 72 | screen = np.frombuffer(signedIntsArray, dtype='uint8') 73 | screen.shape = (h, w, 4) 74 | screen = cv2.cvtColor(screen, cv2.COLOR_BGRA2BGR) 75 | return screen 76 | 77 | def press(self,key): 78 | print(key.char) 79 | # if(key.char=="q"): 80 | # return sys.exit(0) 81 | 82 | def plt_show0(self,img): 83 | b, g, r = cv2.split(img) 84 | img = cv2.merge([r, g, b]) 85 | plt.imshow(img) 86 | plt.show() 87 | 88 | def plt_show(self,img): 89 | plt.imshow(img, cmap="gray") 90 | plt.show() 91 | 92 | 93 | def get_pos(self,contours): 94 | pos_list = [] 95 | for contour in contours: 96 | rect = cv2.boundingRect(contour) 97 | x, y, weight, height = rect 98 | pos_list.append([x, y + height]) 99 | return pos_list 100 | 101 | def speed_pos(self,contours, Min_Area=6500): 102 | chunk_contours = [] 103 | for item in contours: 104 | if cv2.contourArea(item) > Min_Area: 105 | # 用最小巨型进行包裹 106 | rect = cv2.boundingRect(item) 107 | x, y, weight, height = rect 108 | if (height > 120): 109 | for next_y in range(int(height / 120) + 1): 110 | next_y += 1 111 | chunk_contours.append([x + weight / 8, y + 120 * next_y]) 112 | else: 113 | chunk_contours.append([x + weight / 8, y + height]) 114 | return chunk_contours 115 | def start(self): 116 | max_win_width=GetSystemMetrics(SM_CXSCREEN) 117 | max_win_height=GetSystemMetrics(SM_CYSCREEN) 118 | img=self.windowshots(0,0,max_win_width,max_win_height) 119 | cv2.namedWindow("image",cv2.WINDOW_KEEPRATIO) 120 | cv2.setMouseCallback("image", self.on_EVENT_LBUTTONDOWN) 121 | cv2.imshow("image",img) 122 | cv2.waitKey(0) 123 | time.sleep(0.5) 124 | # print(self.clock_number) 125 | while(1): 126 | # global center_post_list 127 | # hwnd = 0 128 | # st = time.time() 129 | img = self.windowshots(self.first_pointX,self.first_pointY,self.second_pointX,self.second_pointY) 130 | # cv2.imshow("test",img) 131 | # cv2.waitKey() 132 | # et = time.time() - st 133 | # FPS = 1//et 134 | img=np.asarray(img) 135 | cv2.imwrite("image.png", img) 136 | img_gray=img.copy() 137 | img_gray=cv2.cvtColor(img_gray,cv2.COLOR_BGR2GRAY) 138 | ret,img_threshold=cv2.threshold(img_gray,60,255,cv2.THRESH_BINARY_INV) 139 | kernelY=cv2.getStructuringElement(cv2.MORPH_RECT,(5,7)) 140 | image = cv2.morphologyEx(img_threshold, cv2.MORPH_CLOSE, kernelY, iterations=1) 141 | kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) 142 | image = cv2.erode(image, kernelX) 143 | contours,hierarchy=cv2.findContours(image,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 144 | self.center_post_list=self.speed_pos(contours) 145 | self.center_post_list=sorted(self.center_post_list, key=lambda tup: tup[1],reverse=True) 146 | if (len(self.center_post_list)==0): 147 | break 148 | 149 | def work(self): 150 | while (1): 151 | for pos in self.center_post_list: 152 | print(self.center_post_list) 153 | pyautogui.moveTo(int(pos[0] + self.first_pointX), int(pos[1] +self.first_pointY), duration=0) 154 | pyautogui.click() 155 | break 156 | if __name__ == '__main__': 157 | Start=GameStart() 158 | t1 = threading.Thread(target=Start.start) 159 | 160 | t2 = threading.Thread(target=Start.work) 161 | t1.start() 162 | t2.start() 163 | # t1.join() 164 | # t2.join() -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mohenghui/python-opencv_block/b584bfeccd81a9a8e33cce9b1e34b0a287c2769a/image.png --------------------------------------------------------------------------------