def _tactical_animation_running(self): """ Detect the white dash line under student cards. If student learning in progress or position haven't been unlocked, there will be a white line under the card. The card with animation running, white line become gray. Returns: bool: If showing skill points increasing animation. """ # Area of the white line under student cards. area = (360, 680, 1280, 700) mask = color_similarity_2d(self.image_area(area), color=(255, 255, 255)) > 235 points = np.array(np.where(mask)).T # Width of card is 200 px points = Points(points).group(threshold=210) card = len(points) if card == 0: logger.warning('No student card found.') return False elif card == 3: return True elif card == 4: return False else: logger.warning(f'Unexpected amount of student cards: {card}') return False
def campaign_match_multi(self, template, image, stage_image=None, name_offset=(75, 9), name_size=(60, 16), name_letter=(255, 255, 255), name_thresh=128): """ Args: template (Template): image: Screenshot stage_image: Screenshot to find stage entrance. name_offset (tuple[int]): name_size (tuple[int]): name_letter (tuple[int]): name_thresh (int): Returns: list[Button]: Stage clear buttons. """ digits = [] stage_image = image if stage_image is None else stage_image result = template.match_multi(stage_image, similarity=0.85) result = Points(result, config=self.config).group() for point in result: button = tuple(np.append(point, point + template.size)) point = point + name_offset name = image.crop(np.append(point, point + name_size)) name = extract_letters(name, letter=name_letter, threshold=name_thresh) stage = self._extract_stage_name(name) area = area_offset(stage, point) color = get_color(image, button) digits.append(Button(area=area, color=color, button=button, name='stage')) return digits
def match_multi(self, image, similarity=0.85, threshold=3, name=None): """ Args: image: similarity (float): 0 to 1. threshold (int): Distance to delete nearby results. name (str): Returns: list[Button]: """ raw = image if self.is_gif: result = [] for template in self.image: res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED) res = np.array(np.where(res > similarity)).T[:, ::-1].tolist() result += res else: result = cv2.matchTemplate(image, self.image, cv2.TM_CCOEFF_NORMED) result = np.array(np.where(result > similarity)).T[:, ::-1] # result: np.array([[x0, y0], [x1, y1], ...) result = Points(result).group(threshold=threshold) return [ self._point_to_button(point, image=raw, name=name) for point in result ]
def _dorm_receive_click(self): """ Click coins and loves in dorm. Returns: int: Receive count. Pages: in: page_dorm out: page_dorm, with info_bar """ image = MASK_DORM.apply(np.array(self.device.image)) love_points = Points(TEMPLATE_DORM_LOVE.match_multi(image), config=self.config).group() coin_points = Points(TEMPLATE_DORM_COIN.match_multi(image), config=self.config).group() logger.info( f'Dorm loves: {len(love_points)}, Dorm coins: {len(coin_points)}') count = 0 for point in love_points: button = tuple(np.append(point, point + TEMPLATE_DORM_LOVE.size)) button = Button(area=button, color=(), button=button, name='DORM_LOVE') count += 1 # Disable click record check, because may have too many coins or loves. self.device.click(button, record_check=False) self.device.sleep((0.5, 0.8)) for point in coin_points: button = tuple(np.append(point, point + TEMPLATE_DORM_LOVE.size)) button = Button(area=button, color=(), button=button, name='DORM_COIN') count += 1 self.device.click(button, record_check=False) self.device.sleep((0.5, 0.8)) return count
def _get_medals(self): """ Returns: np.array: [[x1, y1], [x2, y2]], location of the medal icon upper-left corner. """ left_column = self.image_crop((489, 256, 1120, 572)) medals = TEMPLATE_MEDAL_ICON.match_multi(left_column, similarity=0.5, threshold=5) medals = Points([(0., m.area[1]) for m in medals]).group(threshold=5) logger.attr('Medals_icon', len(medals)) return medals
def guild_lobby_get_report(self): """ Returns: Button: Button to enter guild report. """ # Find red color in the area of GUILD_REPORT_AVAILABLE image = color_similarity_2d(self.image_crop(GUILD_REPORT_AVAILABLE), color=(255, 8, 8)) points = np.array(np.where(image > 221)).T[:, ::-1] if len(points): # The center of red dot points = Points(points).group(threshold=40) + GUILD_REPORT_AVAILABLE.area[:2] # Shift to the center of report icon area = area_offset((-51, -45, -13, 0), offset=points[0]) return Button(area=area, color=(255, 255, 255), button=area, name='GUILD_REPORT') else: return None
def _guild_operation_get_entrance(self): """ Get 2 entrance button of guild dispatch If operation is on the top, after clicking expand button, operation chain moves downward, and enter button appears on the top. So we need to detect two buttons in real time. Returns: list[Button], list[Button]: Expand button, enter button Pages: in: page_guild, guild operation, operation map (GUILD_OPERATIONS_ACTIVE_CHECK) """ # Where whole operation mission chain is detection_area = (152, 135, 1280, 630) # Offset inside to avoid clicking on edge pad = 5 def point_to_entrance_1(point): """ Get expand button """ area = area_limit( area_offset(area=(-257, 14, 12, 51), offset=point), detection_area) return Button(area=area, color=(), button=area_pad(area, pad), name='DISPATCH_ENTRANCE_1') def point_to_entrance_2(point): """ Get enter button """ area = area_limit( area_offset(area=(-257, -109, 12, -1), offset=point), detection_area) return Button(area=area, color=(), button=area_pad(area, pad), name='DISPATCH_ENTRANCE_2') # Scan image and must have similarity greater than 0.85 points = TEMPLATE_OPERATIONS_RED_DOT.match_multi( self.device.image.crop(detection_area)) points += detection_area[:2] points = Points(points, config=self.config).group(threshold=5) logger.info(f'Active operations found: {len(points)}') return [point_to_entrance_1(point) for point in points ], [point_to_entrance_2(point) for point in points]