Richard Köhl 1 rok pred
commit
e341b563c6

+ 18 - 0
capture.py

@@ -0,0 +1,18 @@
+import datetime
+from ppadb.client import Client as AdbClient
+
+client = AdbClient(host="127.0.0.1", port=5037)
+device = client.device("192.168.178.32:5555")
+
+def save_screenshot():
+  # Take a screenshot
+  result = device.screencap()
+
+  timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
+  filename = f"fights/{timestamp}.png"
+
+  # Save the screenshot to a file
+  with open(filename, "wb") as fp:
+      fp.write(result)
+
+save_screenshot()

+ 0 - 0
fights/.gitkeep


+ 84 - 0
locate.py

@@ -0,0 +1,84 @@
+import cv2
+import numpy as np
+
+def non_max_suppression(boxes, overlapThresh):
+    if len(boxes) == 0:
+        return []
+
+    # Convert to float
+    boxes = np.array(boxes, dtype="float")
+
+    # Initialize the list of picked indexes
+    pick = []
+
+    # Grab the coordinates of the bounding boxes
+    x1 = boxes[:,0]
+    y1 = boxes[:,1]
+    x2 = boxes[:,2]
+    y2 = boxes[:,3]
+
+    # Compute the area of the bounding boxes and sort by bottom-right y-coordinate
+    area = (x2 - x1 + 1) * (y2 - y1 + 1)
+    idxs = np.argsort(y2)
+
+    # Keep looping while some indexes still remain in the indexes list
+    while len(idxs) > 0:
+        # Grab the last index in the indexes list and add the index value to the list of picked indexes
+        last = len(idxs) - 1
+        i = idxs[last]
+        pick.append(i)
+
+        # Find the largest (x, y) coordinates for the start of the bounding box and the smallest (x, y)
+        # coordinates for the end of the bounding box
+        xx1 = np.maximum(x1[i], x1[idxs[:last]])
+        yy1 = np.maximum(y1[i], y1[idxs[:last]])
+        xx2 = np.minimum(x2[i], x2[idxs[:last]])
+        yy2 = np.minimum(y2[i], y2[idxs[:last]])
+
+        # Compute the width and height of the bounding box
+        w = np.maximum(0, xx2 - xx1 + 1)
+        h = np.maximum(0, yy2 - yy1 + 1)
+
+        # Compute the ratio of overlap
+        overlap = (w * h) / area[idxs[:last]]
+
+        # Delete all indexes from the index list that have overlap greater than the threshold
+        idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0])))
+
+    # Return only the bounding boxes that were picked
+    return boxes[pick].astype("int")
+
+# Load images
+target_image = cv2.imread('test/20240108_021855.png')
+template_image = cv2.imread('templates/end_of_log.jpg')
+w, h = template_image.shape[:-1]
+
+# Template matching
+result = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)
+
+# Define a threshold
+threshold = 0.9  # Adjust this threshold based on your requirements
+
+# Finding all locations where match exceeds threshold
+locations = np.where(result >= threshold)
+locations = list(zip(*locations[::-1]))
+
+# Create list of rectangles
+rectangles = [(*loc, loc[0] + w, loc[1] + h) for loc in locations]
+
+# Apply non-maximum suppression to remove overlaps
+rectangles = non_max_suppression(rectangles, 0.3)
+
+# Draw rectangles around matches
+for (startX, startY, endX, endY) in rectangles:
+    cv2.rectangle(target_image, (startX, startY), (endX, endY), (0, 255, 0), 2)
+
+    # Print the coordinates of the rectangle
+    centerX = round(startX + (endX-startX)/2)
+    centerY = round(startY + (endY-startY)/2)
+    print(f"center coordinates: {centerX}/{centerY}")
+
+# Display the result
+cv2.imshow('Matched Results', target_image)
+cv2.waitKey(0)
+cv2.destroyAllWindows()

+ 210 - 0
screenshot.py

@@ -0,0 +1,210 @@
+import cv2
+import time
+import datetime
+import numpy as np
+from PIL import Image
+from io import BytesIO
+from ppadb.client import Client as AdbClient
+
+client = AdbClient(host="127.0.0.1", port=5037)
+device = client.device("192.168.178.32:5555")
+
+# template positions
+close_sub_fights = cv2.imread('templates/close_sub_fights.jpg')
+close_fight = cv2.imread('templates/close_fight.jpg')
+fight_button = cv2.imread('templates/i.jpg')
+end_of_log = cv2.imread('templates/end_of_log.jpg')
+
+# cursor positions
+fight_scroll_top = "2494 626"
+titan_fight = "1400 860"
+damage_taken = "450 850"
+close_details = "2175 450"
+close_titan_fight = "2650 570"
+
+def non_max_suppression(boxes, overlapThresh):
+  if len(boxes) == 0:
+    return []
+
+  # Convert to float
+  boxes = np.array(boxes, dtype="float")
+
+  # Initialize the list of picked indexes
+  pick = []
+
+  # Grab the coordinates of the bounding boxes
+  x1 = boxes[:,0]
+  y1 = boxes[:,1]
+  x2 = boxes[:,2]
+  y2 = boxes[:,3]
+
+  # Compute the area of the bounding boxes and sort by bottom-right y-coordinate
+  area = (x2 - x1 + 1) * (y2 - y1 + 1)
+  idxs = np.argsort(y2)
+
+  # Keep looping while some indexes still remain in the indexes list
+  while len(idxs) > 0:
+    # Grab the last index in the indexes list and add the index value to the list of picked indexes
+    last = len(idxs) - 1
+    i = idxs[last]
+    pick.append(i)
+
+    # Find the largest (x, y) coordinates for the start of the bounding box and the smallest (x, y)
+    # coordinates for the end of the bounding box
+    xx1 = np.maximum(x1[i], x1[idxs[:last]])
+    yy1 = np.maximum(y1[i], y1[idxs[:last]])
+    xx2 = np.minimum(x2[i], x2[idxs[:last]])
+    yy2 = np.minimum(y2[i], y2[idxs[:last]])
+
+    # Compute the width and height of the bounding box
+    w = np.maximum(0, xx2 - xx1 + 1)
+    h = np.maximum(0, yy2 - yy1 + 1)
+
+    # Compute the ratio of overlap
+    overlap = (w * h) / area[idxs[:last]]
+
+    # Delete all indexes from the index list that have overlap greater than the threshold
+    idxs = np.delete(idxs, np.concatenate(([last], np.where(overlap > overlapThresh)[0])))
+
+  # Return only the bounding boxes that were picked
+  return boxes[pick].astype("int")
+
+def screen_has_changed(prev_screenshot, threshold=0.01):
+  # Take a new screenshot
+  current_screenshot = device.screencap()
+
+  # Convert to NumPy arrays
+  prev_img = np.frombuffer(prev_screenshot, dtype=np.uint8)
+  current_img = np.frombuffer(current_screenshot, dtype=np.uint8)
+
+  # Load images
+  prev_img = cv2.imdecode(prev_img, cv2.IMREAD_COLOR)
+  current_img = cv2.imdecode(current_img, cv2.IMREAD_COLOR)
+
+  # Calculate absolute difference
+  diff = cv2.absdiff(prev_img, current_img)
+  non_zero_count = np.count_nonzero(diff)
+
+  # print(f"diff: {non_zero_count} > {threshold * diff.size} = {non_zero_count > threshold * diff.size}")
+
+  # Check if the difference is greater than the threshold
+  return non_zero_count > threshold * diff.size
+
+def save_screenshot():
+  # Take a screenshot
+  result = device.screencap()
+
+  timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
+  filename = f"fights/{timestamp}.png"
+
+  # Save the screenshot to a file
+  with open(filename, "wb") as fp:
+    fp.write(result)
+
+  time.sleep(0.5)
+
+def wait_for_screen_change():
+  # Usage example
+  prev_screenshot = device.screencap()
+
+  while not screen_has_changed(prev_screenshot):
+    time.sleep(0.1)  # Polling interval
+
+def tap(location):
+  device.shell(f"input tap {location}")
+  time.sleep(1)
+
+def swipe(start, end):
+  device.shell(f"input swipe {start} {end} 1000")
+  time.sleep(0.5)
+
+def tap_button(template):
+  button = find_templates(template)
+  if len(button) == 0:
+    return
+  tap(f"{button[0][0]} {button[0][1]}")
+
+def is_end_of_log(template):
+  templates = find_templates(template)
+  result = len(templates) > 0
+  if result:
+    print(templates)
+    print("reached end of guild war log!")
+
+  return result
+
+def find_templates(template_image):
+  screenshot = device.screencap()
+  target_image = Image.open(BytesIO(screenshot))
+
+  # Convert the image to a NumPy array and then to BGR format (which OpenCV uses)
+  target_image = np.array(target_image)
+  target_image = cv2.cvtColor(target_image, cv2.COLOR_RGB2BGR)
+
+  w, h = template_image.shape[:-1]
+
+  # Template matching
+  result = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)
+
+  # Define a threshold
+  threshold = 0.9  # Adjust this threshold based on your requirements
+
+  # Finding all locations where match exceeds threshold
+  locations = np.where(result >= threshold)
+  locations = list(zip(*locations[::-1]))
+
+  # Create list of rectangles
+  rectangles = [(*loc, loc[0] + w, loc[1] + h) for loc in locations]
+
+  # Apply non-maximum suppression to remove overlaps
+  rectangles = non_max_suppression(rectangles, 0.3)
+
+  # Initialize an empty list to store coordinates
+  coordinates = []
+
+  for (startX, startY, endX, endY) in rectangles:
+      # Calculate the center coordinates
+      centerX = round(startX + (endX - startX) / 2)
+      centerY = round(startY + (endY - startY) / 2)
+
+      # Append the coordinate pair to the list
+      coordinates.append((centerX, centerY))
+
+  return coordinates
+
+def find_max_y_pair(coordinates):
+    # find the coordinate pair with the maximum y value
+    result = max(coordinates, key=lambda x: x[1])
+
+    return f"{result[0]} {result[1]}"
+
+def take_fight_screenshots():
+  save_screenshot()
+  tap(damage_taken)
+  save_screenshot()
+  tap_button(close_fight)
+
+def process_war_log():
+  buttons = find_templates(fight_button)
+
+  # process all found buttons
+  for pair in buttons:
+      tap(f"{pair[0]} {pair[1]}")
+      sub_buttons = find_templates(fight_button)
+      if (len(sub_buttons) == 0):
+        take_fight_screenshots()
+      else:
+        for pair2 in sub_buttons:
+          tap(f"{pair2[0]} {pair2[1]}")
+          take_fight_screenshots()
+        tap_button(close_sub_fights)
+
+  find_max_y_pair(buttons)
+  swipe(find_max_y_pair(buttons), fight_scroll_top)
+
+# start
+while True:
+  process_war_log();
+
+  if is_end_of_log(end_of_log):
+    break;

BIN
templates/close_fight.jpg


BIN
templates/close_sub_fights.jpg


BIN
templates/end_of_log.jpg


BIN
templates/i.jpg


BIN
test/20240107_234553.png


BIN
test/20240107_234554.png


BIN
test/20240107_235304.png


BIN
test/20240108_002937.png


BIN
test/20240108_012836.png


BIN
test/20240108_014016.png


BIN
test/20240108_015115.png


BIN
test/20240108_021757.png


BIN
test/20240108_021855.png