imgFind.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. # -*- coding: utf-8 -*-
  2. import pyautogui
  3. import random
  4. import time
  5. import numpy as np
  6. import cv2
  7. from PIL import Image
  8. import pyscreeze
  9. pyscreeze.USE_IMAGE_NOT_FOUND_EXCEPTION = False
  10. g_isDown = False
  11. def set_isDown(value):
  12. global g_isDown
  13. g_isDown = value
  14. def color_string_to_rgb(color_string):
  15. r = int(color_string[0:2], 16)
  16. g = int(color_string[2:4], 16)
  17. b = int(color_string[4:6], 16)
  18. return (r, g, b)
  19. def savePic(screenshot, fileName):
  20. image = Image.frombytes('RGB', screenshot.size, screenshot.bgra, 'raw', 'BGRX')
  21. image.save(fileName) # 保存为PNG格式的图像文件
  22. def find_center_point(pointArr):
  23. min_distance = float('inf')
  24. center_point = None
  25. for point in pointArr:
  26. total_distance = 0
  27. for other_point in pointArr:
  28. distance = ((other_point[0] - point[0]) ** 2 + (other_point[1] - point[1]) ** 2) ** 0.5
  29. total_distance += distance
  30. if total_distance < min_distance:
  31. min_distance = total_distance
  32. center_point = point
  33. return center_point
  34. class pcacc_img:
  35. def __init__(specifically):
  36. random.seed()
  37. @staticmethod
  38. def find_maxColor_position(cur_region, colorArr): #(left, top, width, height)
  39. left = cur_region[0]
  40. top = cur_region[1]
  41. width = cur_region[2]
  42. height = cur_region[3]
  43. region = (left, top, width, height)
  44. # 目标颜色和容差值
  45. tolerance = 10 # 容差值
  46. # 在指定区域获取屏幕图像
  47. screenshotSrc = pyautogui.screenshot(region=region)
  48. print(region)
  49. screenshot = np.array(screenshotSrc)
  50. dstPointArr = []
  51. # 创建颜色范围的上下界
  52. for color_str in colorArr:
  53. target_color = color_string_to_rgb(color_str)
  54. lower_color = np.array(target_color) - tolerance
  55. upper_color = np.array(target_color) + tolerance
  56. # 在图像中查找匹配的像素
  57. mask = cv2.inRange(screenshot, lower_color, upper_color)
  58. # 显示 mask 图像
  59. #plt.imshow(mask, cmap='gray')
  60. #plt.show()
  61. points = np.transpose(np.where(mask > 0))
  62. if len(points) < 5:
  63. continue
  64. # 转换坐标到全局坐标系
  65. points[:, 0] += region[0]
  66. points[:, 1] += region[1]
  67. '''
  68. # 使用K-means聚类将匹配点分为不同的簇
  69. n_clusters = 5 # 簇的数量,可根据需要进行调整
  70. kmeans = KMeans(n_clusters=n_clusters)
  71. kmeans.fit(points)
  72. # 找到最大的簇
  73. max_cluster_label = np.argmax(np.bincount(kmeans.labels_))
  74. max_cluster_points = points[kmeans.labels_ == max_cluster_label]
  75. '''
  76. # 输出最集中的像素区域的位置
  77. for point in points:
  78. dstPointArr.append(point)
  79. if len(dstPointArr) > 0:
  80. return True, find_center_point(dstPointArr)
  81. else:
  82. return False, (-1, -1)
  83. @staticmethod
  84. def find_img_position(image_path):
  85. # 设置查找的置信度(confidence)阈值,范围从0到1,默认为0.999
  86. confidence_threshold = 0.85
  87. # 查找模糊图片在屏幕上的位置
  88. position = pyautogui.locateOnScreen(image_path, confidence=confidence_threshold)
  89. if position is not None:
  90. return True, position
  91. else:
  92. return False, None
  93. @staticmethod
  94. def choose_two_point_from_position(position):
  95. dst_x1 = random.randint(position.left, position.left + position.width)
  96. dst_y1 = random.randint(position.top, position.top + position.height)
  97. dst_x2 = random.randint(position.left, position.left + position.width)
  98. dst_y2 = random.randint(position.top, position.top + position.height)
  99. return (dst_x1, dst_y1), (dst_x2, dst_y2)
  100. @staticmethod
  101. def choose_one_point_from_position(position):
  102. dst_x1 = random.randint(position.left, position.left + position.width)
  103. dst_y1 = random.randint(position.top, position.top + position.height)
  104. return (dst_x1, dst_y1)
  105. @staticmethod
  106. def find_all_img(image_path):
  107. # 设置查找的置信度(confidence)阈值,范围从0到1,默认为0.999
  108. confidence_threshold = 0.95
  109. # 查找模糊图片在屏幕上的位置
  110. positions = pyautogui.locateAllOnScreen(image_path, confidence=confidence_threshold)
  111. if len(positions) == 0:
  112. return False, []
  113. return True, positions
  114. @staticmethod
  115. def find_img_cv(image_path, region=None, search_order='bottom-up'):
  116. """
  117. 改进版的模板匹配函数,支持从下往上搜索
  118. :param image_path: 模板图片路径
  119. :param region: 截图区域 (left, top, width, height)
  120. :param search_order: 搜索顺序 ('top-down'或'bottom-up')
  121. :return: (是否找到, 随机点坐标)
  122. """
  123. # 读取模板和屏幕截图
  124. confidence_threshold = 0.95
  125. template = cv2.imread(image_path, cv2.IMREAD_COLOR)
  126. screenshot = cv2.cvtColor(np.array(pyautogui.screenshot(region=region)), cv2.COLOR_RGB2BGR)
  127. # 模板匹配
  128. result = cv2.matchTemplate(screenshot, template, cv2.TM_CCOEFF_NORMED)
  129. width, height = template.shape[1], template.shape[0]
  130. # 获取所有匹配位置[3,5](@ref)
  131. loc = np.where(result >= confidence_threshold)
  132. matches = list(zip(*loc[::-1])) # 转换为(x,y)坐标列表
  133. if len(matches) == 0:
  134. print(f"{image_path} cv图片未找到")
  135. return False, (-1, -1)
  136. # 根据搜索顺序排序匹配结果[7](@ref)
  137. if search_order == 'bottom-up':
  138. # 从下往上排序:先按y坐标降序,再按x坐标升序
  139. matches.sort(key=lambda m: (-m[1], m[0]))
  140. else: # 默认从上往下
  141. matches.sort(key=lambda m: (m[1], m[0]))
  142. # 选择第一个匹配结果(根据搜索顺序)
  143. left, top = matches[0]
  144. # 计算中间区域(避免点击边缘)
  145. mid_left = int(left + width / 4)
  146. mid_right = int(left + width / 4 * 3)
  147. mid_top = int(top + height / 4)
  148. mid_bottom = int(top + height / 4 * 3)
  149. # 生成随机点击位置
  150. want_x = random.randint(mid_left, mid_right)
  151. want_y = random.randint(mid_top, mid_bottom)
  152. # 添加随机偏移(避免每次都点击相同位置)
  153. dst_x = random.randint(int(want_x - width / 3), int(want_x + width / 3))
  154. dst_y = random.randint(int(want_y - height / 3), int(want_y + height / 3))
  155. print(f"{image_path}:({dst_x}, {dst_y}) [搜索顺序: {search_order}]")
  156. return True, (dst_x, dst_y)
  157. @staticmethod
  158. def find_img_origin(image_path):
  159. # 设置查找的置信度(confidence)阈值,范围从0到1,默认为0.999
  160. confidence_threshold = 0.95
  161. # 查找模糊图片在屏幕上的位置
  162. position = pyautogui.locateOnScreen(image_path, confidence=confidence_threshold)
  163. if position is not None:
  164. #dst_position
  165. dst_x = position.left
  166. dst_y = position.top
  167. print(f"{image_path} origin:({dst_x}, {dst_y})")
  168. return True, (dst_x, dst_y)
  169. else:
  170. print(f"{image_path} origin:图片未找到")
  171. return False, (-1, -1)
  172. def find_img_down(image_path):
  173. # 设置查找的置信度(confidence)阈值,范围从0到1,默认为0.999
  174. confidence_threshold = 0.95
  175. # 查找模糊图片在屏幕上的位置
  176. positionAll = pyautogui.locateAllOnScreen(image_path, confidence=confidence_threshold)
  177. location_list = list(positionAll)
  178. localtion_sort = sorted(location_list, key=lambda x: x.top, reverse=True)
  179. if len(localtion_sort) == 0:
  180. return False, (-1, -1)
  181. position = localtion_sort[0]
  182. if position is not None:
  183. # 图片找到了,获取图片的中心点坐标
  184. #mid
  185. mid_left = int(position.left + position.width / 4)
  186. mid_right = int(position.left + position.width / 4 * 3)
  187. mid_top = int(position.top + position.height / 4)
  188. mid_bottom = int(position.top + position.height / 4 * 3)
  189. #want_position
  190. want_x = random.randint(mid_left, mid_right)
  191. want_y = random.randint(mid_top, mid_bottom)
  192. #dst_position
  193. dst_x = random.randint(int(want_x - position.width / 3), int(want_x + position.width / 3))
  194. dst_y = random.randint(int(want_y - position.height / 3), int(want_y + position.height / 3))
  195. print(f"down {image_path}:({dst_x}, {dst_y})")
  196. return True, (dst_x, dst_y)
  197. else:
  198. print(f"{image_path} down图片未找到")
  199. return False, (-1, -1)
  200. def find_img(image_path):
  201. # 设置查找的置信度(confidence)阈值,范围从0到1,默认为0.999
  202. confidence_threshold = 0.92
  203. # 查找模糊图片在屏幕上的位置
  204. position = pyautogui.locateOnScreen(image_path, confidence=confidence_threshold)
  205. if position is not None:
  206. # 图片找到了,获取图片的中心点坐标
  207. #mid
  208. mid_left = int(position.left + position.width / 4)
  209. mid_right = int(position.left + position.width / 4 * 3)
  210. mid_top = int(position.top + position.height / 4)
  211. mid_bottom = int(position.top + position.height / 4 * 3)
  212. #want_position
  213. want_x = random.randint(mid_left, mid_right)
  214. want_y = random.randint(mid_top, mid_bottom)
  215. #dst_position
  216. dst_x = random.randint(int(want_x - position.width / 3), int(want_x + position.width / 3))
  217. dst_y = random.randint(int(want_y - position.height / 3), int(want_y + position.height / 3))
  218. print(f"{image_path}:({dst_x}, {dst_y})")
  219. return True, (dst_x, dst_y)
  220. else:
  221. print(f"{image_path}图片未找到")
  222. return False, (-1, -1)
  223. @staticmethod
  224. def find_imgArr(imgArr):
  225. global g_isDown
  226. for cur_img in imgArr:
  227. if g_isDown:
  228. ret, pos = pcacc_img.find_img_down(cur_img)
  229. else:
  230. ret, pos = pcacc_img.find_img(cur_img)
  231. if ret:
  232. return ret, pos
  233. return False, None
  234. @staticmethod
  235. def find_imgArr_cv(imgArr):
  236. for cur_img in imgArr:
  237. ret, pos = pcacc_img.find_img_cv(cur_img)
  238. if ret:
  239. return ret, pos
  240. return False, None
  241. @staticmethod
  242. def find_imgs(images, is_cv=False):
  243. global g_isDown
  244. if is_cv:
  245. return pcacc_img.find_imgs_cv(images)
  246. else:
  247. if isinstance(images, str):
  248. if g_isDown:
  249. return pcacc_img.find_img_down(images)
  250. else:
  251. return pcacc_img.find_img(images)
  252. elif isinstance(images, (list, tuple)):
  253. return pcacc_img.find_imgArr(images)
  254. else:
  255. raise ValueError("Invalid input type for 'images' parameter.")
  256. @staticmethod
  257. def find_imgs_cv(images):
  258. if isinstance(images, str):
  259. return pcacc_img.find_img_cv(images)
  260. elif isinstance(images, (list, tuple)):
  261. return pcacc_img.find_imgArr_cv(images)
  262. else:
  263. raise ValueError("Invalid input type for 'images' parameter.")
  264. @staticmethod
  265. def find_all_image_locations(image):
  266. confidence_threshold = 0.90
  267. # 查找所有符合条件的图片位置
  268. locations = pyautogui.locateAllOnScreen(image, confidence=confidence_threshold)
  269. # 将位置信息保存到列表中
  270. image_locations = []
  271. for location in locations:
  272. # 获取位置信息的左上角坐标和宽高
  273. x, y, width, height = location
  274. # 将位置信息添加到列表中
  275. image_locations.append((x, y, width, height))
  276. return image_locations
  277. @staticmethod
  278. def find_img_in_area(image,region=None):
  279. confidence_threshold = 0.85
  280. location = pyautogui.locateOnScreen(image,region=region, confidence=confidence_threshold)
  281. if location is not None:
  282. return True
  283. return False
  284. if __name__ == '__main__':
  285. time.sleep(2)
  286. begin = time.time()
  287. pcacc_img.find_maxColor_position((200, 200, 800, 200), {'2EA043'})
  288. cost = time.time() - begin
  289. print("函数执行耗时:", cost, "秒")