screenshot.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import cv2
  2. import time
  3. import datetime
  4. import numpy as np
  5. from PIL import Image
  6. from io import BytesIO
  7. from ppadb.client import Client as AdbClient
  8. client = AdbClient(host="127.0.0.1", port=5037)
  9. device = client.device("192.168.178.32:5555")
  10. # template positions
  11. close_sub_fights = cv2.imread('templates/close_sub_fights.jpg')
  12. close_fight = cv2.imread('templates/close_fight.jpg')
  13. fight_button = cv2.imread('templates/i.jpg')
  14. end_of_log = cv2.imread('templates/end_of_log.jpg')
  15. # cursor positions
  16. fight_scroll_top = "2494 626"
  17. titan_fight = "1400 860"
  18. damage_taken = "450 850"
  19. close_details = "2175 450"
  20. close_titan_fight = "2650 570"
  21. def non_max_suppression(boxes, overlapThresh):
  22. if len(boxes) == 0:
  23. return []
  24. # Convert to float
  25. boxes = np.array(boxes, dtype="float")
  26. # Initialize the list of picked indexes
  27. pick = []
  28. # Grab the coordinates of the bounding boxes
  29. x1 = boxes[:,0]
  30. y1 = boxes[:,1]
  31. x2 = boxes[:,2]
  32. y2 = boxes[:,3]
  33. # Compute the area of the bounding boxes and sort by bottom-right y-coordinate
  34. area = (x2 - x1 + 1) * (y2 - y1 + 1)
  35. idxs = np.argsort(y2)
  36. # Keep looping while some indexes still remain in the indexes list
  37. while len(idxs) > 0:
  38. # Grab the last index in the indexes list and add the index value to the list of picked indexes
  39. last = len(idxs) - 1
  40. i = idxs[last]
  41. pick.append(i)
  42. # Find the largest (x, y) coordinates for the start of the bounding box and the smallest (x, y)
  43. # coordinates for the end of the bounding box
  44. xx1 = np.maximum(x1[i], x1[idxs[:last]])
  45. yy1 = np.maximum(y1[i], y1[idxs[:last]])
  46. xx2 = np.minimum(x2[i], x2[idxs[:last]])
  47. yy2 = np.minimum(y2[i], y2[idxs[:last]])
  48. # Compute the width and height of the bounding box
  49. w = np.maximum(0, xx2 - xx1 + 1)
  50. h = np.maximum(0, yy2 - yy1 + 1)
  51. # Compute the ratio of overlap
  52. overlap = (w * h) / area[idxs[:last]]
  53. # Delete all indexes from the index list that have overlap greater than the threshold
  54. idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0])))
  55. # Return only the bounding boxes that were picked
  56. return boxes[pick].astype("int")
  57. def screen_has_changed(prev_screenshot, threshold=0.01):
  58. # Take a new screenshot
  59. current_screenshot = device.screencap()
  60. # Convert to NumPy arrays
  61. prev_img = np.frombuffer(prev_screenshot, dtype=np.uint8)
  62. current_img = np.frombuffer(current_screenshot, dtype=np.uint8)
  63. # Load images
  64. prev_img = cv2.imdecode(prev_img, cv2.IMREAD_COLOR)
  65. current_img = cv2.imdecode(current_img, cv2.IMREAD_COLOR)
  66. # Calculate absolute difference
  67. diff = cv2.absdiff(prev_img, current_img)
  68. non_zero_count = np.count_nonzero(diff)
  69. # print(f"diff: {non_zero_count} > {threshold * diff.size} = {non_zero_count > threshold * diff.size}")
  70. # Check if the difference is greater than the threshold
  71. return non_zero_count > threshold * diff.size
  72. def save_screenshot():
  73. # Take a screenshot
  74. result = device.screencap()
  75. timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
  76. filename = f"fights/{timestamp}.png"
  77. # Save the screenshot to a file
  78. with open(filename, "wb") as fp:
  79. fp.write(result)
  80. time.sleep(0.5)
  81. def wait_for_screen_change():
  82. # Usage example
  83. prev_screenshot = device.screencap()
  84. while not screen_has_changed(prev_screenshot):
  85. time.sleep(0.1) # Polling interval
  86. def tap(location):
  87. device.shell(f"input tap {location}")
  88. time.sleep(1)
  89. def swipe(start, end):
  90. device.shell(f"input swipe {start} {end} 1000")
  91. time.sleep(0.5)
  92. def tap_button(template):
  93. button = find_templates(template)
  94. if len(button) == 0:
  95. return
  96. tap(f"{button[0][0]} {button[0][1]}")
  97. def is_end_of_log(template):
  98. templates = find_templates(template)
  99. result = len(templates) > 0
  100. if result:
  101. print(templates)
  102. print("reached end of guild war log!")
  103. return result
  104. def find_templates(template_image):
  105. screenshot = device.screencap()
  106. target_image = Image.open(BytesIO(screenshot))
  107. # Convert the image to a NumPy array and then to BGR format (which OpenCV uses)
  108. target_image = np.array(target_image)
  109. target_image = cv2.cvtColor(target_image, cv2.COLOR_RGB2BGR)
  110. w, h = template_image.shape[:-1]
  111. # Template matching
  112. result = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)
  113. # Define a threshold
  114. threshold = 0.9 # Adjust this threshold based on your requirements
  115. # Finding all locations where match exceeds threshold
  116. locations = np.where(result >= threshold)
  117. locations = list(zip(*locations[::-1]))
  118. # Create list of rectangles
  119. rectangles = [(*loc, loc[0] + w, loc[1] + h) for loc in locations]
  120. # Apply non-maximum suppression to remove overlaps
  121. rectangles = non_max_suppression(rectangles, 0.3)
  122. # Initialize an empty list to store coordinates
  123. coordinates = []
  124. for (startX, startY, endX, endY) in rectangles:
  125. # Calculate the center coordinates
  126. centerX = round(startX + (endX - startX) / 2)
  127. centerY = round(startY + (endY - startY) / 2)
  128. # Append the coordinate pair to the list
  129. coordinates.append((centerX, centerY))
  130. return coordinates
  131. def find_max_y_pair(coordinates):
  132. # find the coordinate pair with the maximum y value
  133. result = max(coordinates, key=lambda x: x[1])
  134. return f"{result[0]} {result[1]}"
  135. def take_fight_screenshots():
  136. save_screenshot()
  137. tap(damage_taken)
  138. save_screenshot()
  139. tap_button(close_fight)
  140. def process_war_log():
  141. buttons = find_templates(fight_button)
  142. # process all found buttons
  143. for pair in buttons:
  144. tap(f"{pair[0]} {pair[1]}")
  145. sub_buttons = find_templates(fight_button)
  146. if (len(sub_buttons) == 0):
  147. take_fight_screenshots()
  148. else:
  149. for pair2 in sub_buttons:
  150. tap(f"{pair2[0]} {pair2[1]}")
  151. take_fight_screenshots()
  152. tap_button(close_sub_fights)
  153. find_max_y_pair(buttons)
  154. swipe(find_max_y_pair(buttons), fight_scroll_top)
  155. # start
  156. while True:
  157. process_war_log();
  158. if is_end_of_log(end_of_log):
  159. break;