def get_ult_colors_from_image(self): """Get ultimate charge number colors from this frame. Author: Rigel Args: None Returns: @ult_color: array of int, -1: white number, 1: black number """ left_pre_pos = OW.get_ult_charge_color_pre_pos(True)[self.game.game_type] left_pre_image = ImageUtils.rgb_to_gray(ImageUtils.crop(self.image, left_pre_pos)) left_shear = ImageUtils.shear(left_pre_image, OW.get_tf_shear(True)[self.game.game_type]) left_pos = OW.get_ult_charge_color_pos(True)[self.game.game_type] left_image = ImageUtils.crop(left_shear, left_pos) left_image_g = ImageUtils.contrast_adjust_log(left_image, OW.ULT_ADJUST_LOG_INDEX) left_bin = ImageUtils.binary_otsu(left_image_g) right_pre_pos = OW.get_ult_charge_color_pre_pos(False)[self.game.game_type] right_pre_image = ImageUtils.rgb_to_gray(ImageUtils.crop(self.image, right_pre_pos)) right_shear = ImageUtils.shear(right_pre_image, OW.get_tf_shear(False)[self.game.game_type]) right_pos = OW.get_ult_charge_color_pos(False)[self.game.game_type] right_image = ImageUtils.crop(right_shear, right_pos) right_image_g = ImageUtils.contrast_adjust_log(right_image, OW.ULT_ADJUST_LOG_INDEX) right_bin = ImageUtils.binary_otsu(right_image_g) return { "left": np.sign(2 * np.sum(left_bin) - np.size(left_bin)), "right": np.sign(2 * np.sum(right_bin) - np.size(right_bin)) }
def get_ult_status(self): """Retrieves ultimate statues info for current player in current frame. Author: Appcell Args: None Returns: None """ # Crop icon from current frame ult_icon_pos = OW.get_ult_icon_pos( self.index)[self.frame.game.game_type] ult_icon = ImageUtils.crop(self.image, ult_icon_pos) # Get reference icon image ult_icon_ref = OW.get_ult_icon_ref( self.index)[self.frame.game.game_type] # Tranfer both to grayscale for comparison ult_icon_ref, ult_icon = ImageUtils.rgb_to_gray( ult_icon_ref), ImageUtils.rgb_to_gray(ult_icon) # Compare cropped icon with reference, get the probability of them # being similar prob_map = cv2.matchTemplate(ult_icon, ult_icon_ref, cv2.TM_CCOEFF_NORMED) prob_map_cropped = prob_map[0:(ult_icon.shape[0] - ult_icon_ref.shape[0]), :] _, prob, _, loc = cv2.minMaxLoc(prob_map_cropped) # To avoid possible explosion effect. # When ult gets ready, brightness of icon goes above limit. brightness = np.mean(ult_icon) deviation = np.std(ult_icon) if brightness > OW.ULT_ICON_MAX_BRIGHTNESS[self.frame.game.game_type] \ and deviation < OW.ULT_ICON_MAX_DEVIATION[self.frame.game.game_type]: prob = 1 self.is_ult_ready = True return temp_ult_icon = ImageUtils.crop( ult_icon, [loc[1], ult_icon_ref.shape[0], loc[0], ult_icon_ref.shape[1]]) prob_ssim = measure.compare_ssim(temp_ult_icon, ult_icon_ref, multichannel=False) if prob > OW.ULT_ICON_MAX_PROB[self.frame.game.game_type]: if prob_ssim > OW.ULT_ICON_MAX_PROB_SSIM[ self.frame.game.game_type]: self.is_ult_ready = True
def get_ability_icons_ref(): """Read in all ability icons. Author: Appcell Args: None Returns: A dict of all ability icons, with chara names as keys and list of all abilities of this chara as values. """ res_owl = {} res_custom = {} for (chara, ability_list) in ABILITY_LIST.iteritems(): icons_list_owl = [] icons_list_custom = [] for i in ability_list: icon = ImageUtils.rgb_to_gray( ImageUtils.read("./images/abilities/" + chara + "/" + str(i) + ".png")) icons_list_owl.append( ImageUtils.resize(icon, ABILITY_ICON_WIDTH[GAMETYPE_OWL], ABILITY_ICON_HEIGHT[GAMETYPE_OWL])) icons_list_custom.append( ImageUtils.resize(icon, ABILITY_ICON_WIDTH[GAMETYPE_CUSTOM], ABILITY_ICON_HEIGHT[GAMETYPE_CUSTOM])) res_owl[chara] = icons_list_owl res_custom[chara] = icons_list_custom return {GAMETYPE_OWL: res_owl, GAMETYPE_CUSTOM: res_custom}
def get_ult_status(self): """Retrieves ultimate statues info for current player in current frame. Author: Appcell Args: None Returns: None """ # Crop icon from current frame ult_icon_pos = OW.get_ult_icon_pos( self.index)[self.frame.game.game_type] ult_icon = ImageUtils.crop(self.image, ult_icon_pos) # Get reference icon image ult_icon_ref = OW.get_ult_icon_ref( self.index)[self.frame.game.game_type] # Tranfer both to grayscale for comparison ult_icon_ref, ult_icon = ImageUtils.rgb_to_gray( ult_icon_ref), ImageUtils.rgb_to_gray(ult_icon) # Compare cropped icon with reference, get the probability of them # being similar prob = cv2.matchTemplate(ult_icon, ult_icon_ref, cv2.TM_CCOEFF_NORMED).max() # To avoid possible explosion effect. # When ult gets ready, brightness of icon goes above limit. brightness = np.mean(ult_icon) if brightness > OW.ULT_ICON_MAX_BRIGHTNESS[self.frame.game.game_type]: prob = 1 if prob > OW.ULT_ICON_MAX_PROB[self.frame.game.game_type]: self.is_ult_ready = True
def get_ult_charge(self): """Retrieves ultimate charge for current player. Author: Args: None Returns: None """ if self.is_ult_ready: self.ult_charge = 100 return if self.is_dead: return ult_charge_pre_pos = OW.get_ult_charge_pre_pos( self.index)[self.frame.game.game_type] ult_charge_pre_image = ImageUtils.rgb_to_gray( ImageUtils.crop(self.image, ult_charge_pre_pos)) ult_charge_shear = ImageUtils.shear( ult_charge_pre_image, OW.get_tf_shear(self.index)[self.frame.game.game_type]) ult_charges = [0, 0] # Here's another thought: we need to find the gap more intellectually, # not relying only on fixed position. # In detail, after shearing, find the gap by telling if there are more # than 2 colors in same column. ult_charge_image = ImageUtils.crop( ult_charge_shear, OW.get_ult_charge_pos(self.index)[self.frame.game.game_type]) # TODO: I see there's no difference at all of brightness deviation!! # Our contrast adjusting must be seriously problematic. For grayscale # img, a simple normalization based on std would do. # ult_charge_image_g = ImageUtils.contrast_adjust_log( # ult_charge_image, OW.ULT_ADJUST_LOG_INDEX) ult_charge_image_g = ImageUtils.normalize_gray(ult_charge_image) # tell if player is observed (more accurate than previous) # Here I use another local variable flag_observed, since the global one # might be inaccurate flag_observed = False deviation_row = ult_charge_image_g.max( axis=1) - ult_charge_image_g.min(axis=1) if deviation_row[2] - deviation_row[0] > \ OW.ULT_GAP_DEVIATION_LIMIT[self.frame.game.game_type]: self.is_observed = True flag_observed = True # If current player is observed, there's a white dot on right side # needs to be removed. # TODO: write this into ow.py as well if flag_observed is True: ult_charge_image_g = ImageUtils.crop(ult_charge_image_g, [ 0, ult_charge_image_g.shape[0], 0, ult_charge_image_g.shape[1] - 5 ]) width = ult_charge_image_g.shape[1] height = ult_charge_image_g.shape[0] # Find the gap deviation = ult_charge_image_g.max(axis=0) - ult_charge_image_g.min( axis=0) gap = -1 for i in range(width - 4, 3, -1): if deviation[i-3] - deviation[i] \ > OW.ULT_GAP_DEVIATION_LIMIT[self.frame.game.game_type] \ and deviation[i+3] - deviation[i] \ > OW.ULT_GAP_DEVIATION_LIMIT[self.frame.game.game_type]: gap = i break bg_color = ult_charge_image_g[:, 0].mean() if bg_color < 0.6: # Dark background ult_charge_image_g = ImageUtils.inverse_gray(ult_charge_image_g) # No need to switch to BW here. if gap == -1: # Only one digit num = ImageUtils.remove_digit_vertical_edge( ult_charge_image_g, OW.ULT_GAP_DEVIATION_LIMIT[self.frame.game.game_type], ImageUtils.REMOVE_NUMBER_VERTICAL_EDGE_BOTH) else: # 2 digits num_left = ImageUtils.crop( ult_charge_image_g, [0, ult_charge_image_g.shape[0], 0, gap + 1]) num_right = ImageUtils.crop(ult_charge_image_g, [ 0, ult_charge_image_g.shape[0], gap, ult_charge_image_g.shape[1] - gap ]) if flag_observed is True: num_left = ImageUtils.crop( num_left, [0, num_left.shape[0], num_left.shape[1] \ - OW.ULT_CHARGE_NUMBER_WIDTH_OBSERVED[self.frame.game.game_type] - 1, OW.ULT_CHARGE_NUMBER_WIDTH_OBSERVED[self.frame.game.game_type]]) num_right = ImageUtils.crop(num_right, [ 0, num_left.shape[0], 0, OW. ULT_CHARGE_NUMBER_WIDTH_OBSERVED[self.frame.game.game_type] ]) else: num_left = ImageUtils.crop( num_left, [0, num_left.shape[0], num_left.shape[1] \ - OW.ULT_CHARGE_NUMBER_WIDTH_OBSERVED[self.frame.game.game_type] - 1, OW.ULT_CHARGE_NUMBER_WIDTH_OBSERVED[self.frame.game.game_type]]) num_right = ImageUtils.crop(num_right, [ 0, num_left.shape[0], 0, OW. ULT_CHARGE_NUMBER_WIDTH_OBSERVED[self.frame.game.game_type] ]) # if self.index == 5: # cv2.imshow('t1', num_left) # cv2.waitKey(0) # cv2.imshow('t2', num_right) # cv2.waitKey(0) # Since when cropping img we also included the slope on left side, # num_left could actually be empty # Also we need another recognition method. Simple MSE wouldn't work due to error. # ult_charge_image_g = ImageUtils.contrast_adjust_log( # ult_charge_image, OW.ULT_ADJUST_LOG_INDEX) # for i in (0,1): # cv2.imshow('t', ult_charge_image) # cv2.waitKey(0) # try: # ult_charge_image_binary = ImageUtils.binary_otsu(ult_charge_image_g) # except ValueError: # self.ult_charge = None # return # ult_charge_similarities = np.zeros(11) # for j in range(1 - i, 11-i): # # 1st number can't be 0, 2nd number can't be empty # ult_charge_ref = self.frame.game.ult_charge_numbers_ref[j - i] # ult_charge_similarities[j] = ImageUtils.similarity(ult_charge_ref, ult_charge_image_binary) # ult_charges[i] = np.argmax(ult_charge_similarities) # print ult_charges[i] # if ult_charges[i] == 10: # ult_charges[i] = 0 self.ult_charge = ult_charges[0] * 10 + ult_charges[1] return