def match(self, img_arr: np.ndarray) -> int: cursor = self.sqlite_connection.cursor() img_arr_resized = image_process.resize(img_arr, CV_SUPPORT_SERVANT_IMG_SIZE[1], CV_SUPPORT_SERVANT_IMG_SIZE[0]) servant_part = img_arr_resized[:CV_SUPPORT_SERVANT_SPLIT_Y, :, :3] hsv_servant_part = image_process.rgb_to_hsv(servant_part) # querying servant icon database if self.cached_icon_meta is None: cursor.execute( "select id from servant_icon order by id desc limit 1") newest_svt_id = cursor.fetchone()[0] cursor.execute("select count(1) from servant_icon") entries = cursor.fetchone()[0] cursor.execute("select id, image_key from servant_icon") self.cached_icon_meta = cursor.fetchall() logger.info( 'Finished querying support servant database, %d entries with newest servant id: %d' % (entries, newest_svt_id)) # querying image data min_servant_id = 0 min_abs_err = 0 for servant_id, image_key in self.cached_icon_meta: if image_key not in self.cached_icons: cursor.execute( "select image_data from image where image_key = ?", (image_key, )) binary_data = cursor.fetchone()[0] # clipping alpha and opacity border np_image = image_process.imdecode(binary_data)[3:-3, 3:-3, :] if np_image.shape[:2] != CV_SUPPORT_SERVANT_IMG_SIZE: if not self.__warn_size_mismatch: self.__warn_size_mismatch = True logger.warning( 'The configuration of image size for support servant matching is different from ' 'database size, performance will decrease: servant id: %d, key: %s' % (servant_id, image_key)) np_image = image_process.resize( np_image, CV_SUPPORT_SERVANT_IMG_SIZE[1], CV_SUPPORT_SERVANT_IMG_SIZE[0]) np_image, alpha = image_process.split_rgb_alpha(np_image) hsv_image = image_process.rgb_to_hsv(np_image) self.cached_icons[image_key] = np.concatenate( [hsv_image, np.expand_dims(alpha, 2)], axis=2) anchor_servant_part = self.cached_icons[ image_key][:CV_SUPPORT_SERVANT_SPLIT_Y, ...] hsv_err = image_process.mean_hsv_diff_err(anchor_servant_part, hsv_servant_part, 'hsv', 'hsv') if min_servant_id == 0 or hsv_err < min_abs_err: min_servant_id = servant_id min_abs_err = hsv_err logger.debug('svt_id = %d, key = %s, hsv_err = %f' % (servant_id, image_key, hsv_err)) cursor.close() return min_servant_id
def get_screenshot(self, width: Optional[int] = None, height: Optional[int] = None) -> np.ndarray: """ Get the current screenshot of simulator. :param width: the width of reshaped screenshot (in pixels), default: window width :param height: the height of reshaped screenshot (in pixels), default: window height :return: returns a numpy array shapes [h, w, c] which c = 3 in RGB order """ left, top, right, bottom = win32gui.GetWindowRect(self.handle()) window_height = bottom - top window_width = right - left handle_dc = win32gui.GetWindowDC(self.handle()) new_dc = win32ui.CreateDCFromHandle(handle_dc) compat_dc = new_dc.CreateCompatibleDC() new_bitmap = win32ui.CreateBitmap() new_bitmap.CreateCompatibleBitmap(new_dc, window_width, window_height) compat_dc.SelectObject(new_bitmap) compat_dc.BitBlt((0, 0), (window_width, window_height), new_dc, (0, 0), win32con.SRCCOPY) arr = new_bitmap.GetBitmapBits(True) arr = np.fromstring(arr, dtype='uint8').reshape([window_height, window_width, -1]) new_dc.DeleteDC() compat_dc.DeleteDC() win32gui.ReleaseDC(self.handle(), handle_dc) win32gui.DeleteObject(new_bitmap.GetHandle()) screenshot = np.flip(arr[..., :3], -1) if width is None: width = window_width if height is None: height = window_height if width != window_width or height != window_width: screenshot = image_process.resize(screenshot, width, height) return screenshot
def get_screenshot(self, width: Optional[int] = None, height: Optional[int] = None) -> np.ndarray: img = self._get_screenshot_internal() width = width or img.shape[1] height = height or img.shape[0] return image_process.resize(img, width, height)
def _craft_essence_empty_check(img1, img2): img1_h = int(img2.shape[1] / img1.shape[1] * img1.shape[0]) img1 = image_process.resize(img1, img2.shape[1], img1_h) img1 = img1[-img2.shape[0]:, ...] v = mean_gray_diff_err(img1, img2) logger.debug('DEBUG value: empty support craft essence check: mean_gray_diff_err = %f' % v) return v < 10
def match(self, img_arr: np.ndarray) -> int: cursor = self.sqlite_connection.cursor() ratio_thresh = 0.7 img_arr_resized = image_process.resize(img_arr, CV_SUPPORT_SERVANT_IMG_SIZE[1], CV_SUPPORT_SERVANT_IMG_SIZE[0]) craft_essence_part = img_arr_resized[CV_SUPPORT_SERVANT_SPLIT_Y:-3, 2:-2, :] # CACHE ACCESS cache_key = self.image_cacher.get(craft_essence_part, None) if cache_key is not None: return cache_key if craft_essence_part in self.image_cacher: return self.image_cacher[craft_essence_part] if self.cached_icon_meta is None: cursor.execute( "select id from craft_essence_icon order by id desc limit 1") newest_craft_essence_id = cursor.fetchone()[0] cursor.execute("select count(1) from craft_essence_icon") entries = cursor.fetchone()[0] cursor.execute("select id, image_key from craft_essence_icon") self.cached_icon_meta = cursor.fetchall() logger.info( 'Finished querying craft essence database, %d entries with newest craft essence id: %d' % (entries, newest_craft_essence_id)) _, target_descriptor = self.sift_detector.detectAndCompute( craft_essence_part, None) max_matches = 0 max_craft_essence_id = 0 for craft_essence_id, image_key in self.cached_icon_meta: if image_key not in self.cached_icons: cursor.execute( "select descriptors from image_sift_descriptor where image_key = ?", (image_key, )) descriptor_blob = cursor.fetchone()[0] # keypoint = [deserialize_cv2_keypoint(x) for x in pickle_loads(keypoint_blob)] descriptors = pickle_loads(descriptor_blob) self.cached_icons[ image_key] = descriptors # {'key_point': keypoint, 'descriptor': descriptors} knn_matches = self.matcher.knnMatch(target_descriptor, self.cached_icons[image_key], 2) # knn_matches = self.matcher.match(target_descriptor, self.cached_icons[image_key]['descriptor']) good_matches = [] for m, n in knn_matches: if m.distance < ratio_thresh * n.distance: good_matches.append(m) len_good_matches = len(good_matches) if len_good_matches > max_matches: max_matches = len_good_matches max_craft_essence_id = craft_essence_id logger.debug('craft_essence_id = %d, sift_matches = %d' % (craft_essence_id, len_good_matches)) cursor.close() self.image_cacher[craft_essence_part] = max_craft_essence_id return max_craft_essence_id
def main(): # =================== 동영상 테스트 ================================ fianl_result_array = [] section_result_array = [] video_path = 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\library_video2.mp4' # video에서 프레임 추출 frame_images = vp.extract_frame_from_video(video_path) # 추출된 프레임에서 글자 영역 찾기 for i, frame in enumerate(frame_images): vp.save_image( ct.get_gray(frame), 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test\\frame_{}.jpg'. format(i)) final_result = [] copy = ct.resize(frame) cropped_images = ct.image_all_process(copy)[1] num = 0 # 한 프레임의 글자 영역들의 텍스트 추출 # 자막들 for con in cropped_images["contours"]: # 프레임에서 추출한 영역들 저장 ct.save_crooped_contours( con, 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test\\fcontours_{}' .format(num)) # 영역들에서 글자 추출 result = reco.extract_text(con) # # 추출된 글자 전처리 후 임시 보관 tmp = txt.text_pre_process(result) if (tmp is not None): final_result.append(tmp) # final_result.append(result) num += 1 # 한 프레임 씩 배열에 저장 fianl_result_array.append(final_result) # 섹션 # 섹션 영역 저장 ct.save_crooped_contours( cropped_images["section"], 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test\\fsection_{}'. format(i)) # 섹션에서 글자 추출 section = reco.extract_text(cropped_images["section"]) # 추출된 글자 전처리 후 저장 section_result_array.append(txt.text_pre_process(section)) # section_result_array.append(section) # 모든 결과 값들 저장 하기 txt.text_save( fianl_result_array, section_result_array, 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test\\fnew3_jjan.csv')
def __getitem__(self, idex): batch_size = self.batch_size image_size = self.image_size images_num = self.images_num inputs = np.zeros((batch_size, image_size, image_size, 3), dtype=np.uint8) if self.inplace: image_size *= 4 outputs = np.zeros((batch_size, image_size, image_size, 3), dtype=np.uint8) path_index = idex * batch_size num = 0 while True: if path_index >= images_num: path_index = path_index % images_num path = str(self.image_paths[path_index]) img = imread(path) h, w, _ = img.shape mini = min(h, w) if mini < image_size: img = resize(img, image_size // mini + 1) h, w, _ = img.shape x = random.randint(0, w - image_size) y = random.randint(0, h - image_size) img = img[y:y + image_size, x:x + image_size] img_LR = LR_image(img, self.de_num, self.inplace) inputs[num] = img_LR outputs[num] = img num += 1 path_index += 1 if num >= batch_size: break return inputs, outputs
def _imread_to_screen_size(path): return image_process.resize(image_process.imread(path), CV_SCREENSHOT_RESOLUTION_X, CV_SCREENSHOT_RESOLUTION_Y)
def main(): # =================== 동영상 테스트 ================================ fianl_result_array = [] section_result_array = [] video_path = 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\library_video2.mp4' # video에서 프레임 추출 frame_images = vp.extract_frame_from_video(video_path) f_len = len(frame_images) # 추출된 프레임에서 글자 영역 찾기 num = 0 num2 = 0 for i, frame in enumerate(frame_images): vp.save_image( frame, 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\frame_{}.jpg'. format(i)) final_result = [] copy = ct.resize(frame) cropped_images = ct.image_all_process(copy) # 섹션 추출 ct.save_crooped_contours( cropped_images[0]["section"], 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\section_{}'. format(i)) for con in cropped_images[0]["contours"]: # 프레임에서 추출한 영역들 저장 (origin 로) ct.save_crooped_contours( con, 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\contours_{}_frame_{}_' .format(num2, i)) num2 += 1 # 한 프레임의 글자 영역들에서 텍스트 추출 과정 시작 for con in cropped_images[1]["contours"]: # 프레임에서 추출한 영역들 저장 (gray-scale로) ct.save_crooped_contours( ct.get_gradient(con), 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\contours_{}_frame_{}_' .format(num, i)) num += 1 judge_result = judge.get_text_image(num, 'final_new/') path_dir = 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\contours' num_text = 0 num_not_text = 0 tmp_result = {} section = {} flie_list = os.listdir(path_dir) flie_list.sort() for j in range(1, num): print(flie_list[j]) second = flie_list[j].split('_')[-2] # 섹션 처리하기 if (second in section.keys()): pass else: section[second] = vision.image_ocr( 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\section_{}.jpg' .format(second)) # 텍스트인 contour 찾아내기 if judge_result[j] == 'text': val = vision.image_ocr( 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\contours/' + flie_list[j]) if second in tmp_result: tmp_result[second] = [tmp_result[second], val] else: tmp_result[second] = val # print('num: %d, text: %s' %(num_text, val)) num_text += 1 # 모든 결과 값들 저장 하기 txt.directory_save( tmp_result, section, 'C:\\Users\\Administrator\\Desktop\\2021_ICT\\test2\\jjan.csv')
def match(self, img_arr: np.ndarray) -> int: blur_radius = 2 cursor = self.sqlite_connection.cursor() target_size = CV_COMMAND_CARD_IMG_SIZE # import matplotlib.pyplot as plt # plt.figure() # plt.imshow(img_arr) # plt.show() img_arr_resized = image_process.resize(img_arr, target_size[1], target_size[0]) img_arr_resized, img_alpha = image_process.split_rgb_alpha( img_arr_resized) # use blur to remove high frequency noise introduced by interpolation, but blurring with alpha channel will # produce some weird artifacts on the edge of alpha, same ops to db images img_arr_resized = image_process.gauss_blur(img_arr_resized, blur_radius) hsv_img = np.concatenate([ image_process.rgb_to_hsv(img_arr_resized), np.expand_dims(img_alpha, 2) ], 2) # querying servant icon database if self.cached_icon_meta is None: cursor.execute( "select id from servant_command_card_icon order by id desc limit 1" ) newest_svt_id = cursor.fetchone()[0] cursor.execute("select count(1) from servant_command_card_icon") entries = cursor.fetchone()[0] cursor.execute( "select id, image_key from servant_command_card_icon") self.cached_icon_meta = cursor.fetchall() logger.info( 'Finished querying servant command card database, %d entries with newest servant id: %d' % (entries, newest_svt_id)) # querying image data min_servant_id = 0 min_err = 0 for servant_id, image_key in self.cached_icon_meta: if image_key not in self.cached_icons: cursor.execute( "select image_data, name from image where image_key = ?", (image_key, )) binary_data, name = cursor.fetchone() # All icon are PNG file with extra alpha channel np_image = image_process.imdecode(binary_data) # split alpha channel assert np_image.shape[ -1] == 4, 'Servant Icon should be RGBA channel' if np_image.shape[:2] != target_size: if not self.__warn_size_mismatch: self.__warn_size_mismatch = True logger.warning( 'The configuration of image size for command card matching is different from ' 'database size, performance will decrease: servant id: %d, key: %s' % (servant_id, image_key)) np_image = image_process.resize(np_image, target_size[1], target_size[0]) np_image = image_process.gauss_blur(np_image, blur_radius) np_image, alpha = image_process.split_rgb_alpha(np_image) hsv_image = image_process.rgb_to_hsv(np_image) # weighted by alpha channel size self.cached_icons[image_key] = np.concatenate( [hsv_image, np.expand_dims(alpha, 2)], 2) anchor = self.cached_icons[image_key] # err_map = image_process.mean_hsv_diff_err_dbg(anchor, hsv_img, 'hsv', 'hsv') hsv_err = image_process.mean_hsv_diff_err(anchor, hsv_img, 'hsv', 'hsv') if min_servant_id == 0 or hsv_err < min_err: min_servant_id = servant_id min_err = hsv_err logger.debug('svt_id = %d, key = %s, hsv_err = %f' % (servant_id, image_key, hsv_err)) cursor.close() return min_servant_id
def callback(ch, method, properties, body): job_id = str(body, 'utf-8') logger.info(" [x] Received %s" % job_id) resize(job_id + '.png') logger.info(" [x] Done") ch.basic_ack(delivery_tag=method.delivery_tag)
def _is_in_requesting_friend_ui(self) -> bool: img = self.attacher.get_screenshot(CV_SCREENSHOT_RESOLUTION_X, CV_SCREENSHOT_RESOLUTION_Y) val = mean_gray_diff_err(image_process.resize(img, self._support_anchor.shape[1], self._support_anchor.shape[0]), self._support_anchor) logger.debug('DEBUG value friend_ui mean_gray_diff_err = %f' % val) return val < 10
def detect_command_cards(img: np.ndarray) -> List[DispatchedCommandCard]: """ Detect in-battle command card for current turn (attack button must be pressed before calling this method!) :param img: In-game screenshot, with shape (h, w, 3) in RGB format or (h, w, 4) in RGBA format (A channel will be ignored) :return: A list containing command card info """ assert len(img.shape) == 3, 'Invalid image shape, expected RGB format' if img.shape[-1] == 4: img = img.shape[..., :3] ret_list = [] # 从者头像与指令卡的padding: Top 25px, Left 42px, Right 42px, Bottom 12px t = time() for card_idx, (x1, x2) in enumerate( zip(CV_COMMAND_CARD_X1S, CV_COMMAND_CARD_X2S)): command_card = img[CV_COMMAND_CARD_Y:, x1:x2, :3].copy() card_type = 0 target_err = float('inf') y_offset = 0 for idx, (command_card_type, offset) in enumerate( zip(CommandCardDetector._command_card_type_anchor, CV_COMMAND_CARD_TYPE_OFFSET)): score = np.empty(CV_COMMAND_CARD_Y_DETECTION_LENGTH, np.float) h = command_card_type.shape[0] for i in range(CV_COMMAND_CARD_Y_DETECTION_LENGTH): y = CV_COMMAND_CARD_Y_DETECTION_OFFSET + i score[i] = image_process.mean_gray_diff_err( command_card[y:y + h, ...], command_card_type) min_score = np.min(score) if min_score < target_err: card_type = idx target_err = min_score y_offset = np.argmin( score ) + CV_COMMAND_CARD_Y_DETECTION_OFFSET - offset + CV_COMMAND_CARD_Y # Extend pixels command_card = img[y_offset - CV_COMMAND_CARD_EXTEND_TOP:y_offset + CV_COMMAND_CARD_EXTEND_BOTTOM + CV_COMMAND_CARD_HEIGHT, x1 - CV_COMMAND_CARD_EXTEND_LEFT:x2 + CV_COMMAND_CARD_EXTEND_RIGHT] # support detection support_part = command_card[ CV_COMMAND_CARD_SUPPORT_Y1:CV_COMMAND_CARD_SUPPORT_Y2, CV_COMMAND_CARD_SUPPORT_X1:CV_COMMAND_CARD_SUPPORT_X2, :] err = image_process.mean_hsv_diff_err( support_part, CommandCardDetector._command_card_support_anchor) logger.debug( 'DEBUG value: command card support detection, hsv_err = %f' % err) is_support = err < CV_COMMAND_CARD_SUPPORT_HSV_THRESHOLD # mask command card: concat RGB with extra alpha channel alpha = CommandCardDetector._command_card_rev_alpha[card_type] if command_card.shape[:2] != alpha.shape[:2]: logger.warning( 'Width or height of command card rect does not match the alpha mask, alpha mask must be' ' updated to obtain best matching accuracy') alpha = image_process.resize(alpha, command_card.shape[1], command_card.shape[0]) CommandCardDetector._command_card_rev_alpha[card_type] = alpha # composite support mask if is_support: alpha = alpha.copy() alpha[CV_COMMAND_CARD_SUPPORT_Y1:CV_COMMAND_CARD_SUPPORT_Y2, CV_COMMAND_CARD_SUPPORT_X1:CV_COMMAND_CARD_SUPPORT_X2] = \ CommandCardDetector._command_card_support_rev_alpha command_card = np.concatenate( [command_card, np.expand_dims(alpha, 2)], 2) servant_id = CommandCardDetector._servant_matcher.match( command_card) ret_list.append( DispatchedCommandCard(servant_id, CommandCardType(card_type + 1), card_idx, is_support, 0)) logger.info('Detected command card data: %s (used %f sec(s))' % (str(ret_list), time() - t)) return ret_list
def _servant_empty_check(img1, img2): v = mean_gray_diff_err(image_process.resize(img1, img2.shape[1], img2.shape[0]), img2) logger.debug('DEBUG value: empty support servant check: mean_gray_diff_err = %f' % v) return v < 10
def match_support_servant(self, img: np.ndarray, range_list: List[Tuple[int, int]]) -> List[SupportServant]: # match servant def _servant_empty_check(img1, img2): v = mean_gray_diff_err(image_process.resize(img1, img2.shape[1], img2.shape[0]), img2) logger.debug('DEBUG value: empty support servant check: mean_gray_diff_err = %f' % v) return v < 10 svt_id, t = self._wrap_call_matcher(self.servant_matcher.match, _servant_empty_check, img, self._support_empty_img, range_list) logger.debug('Detected support servant ID: %s (used %f sec(s))' % (str(svt_id), t)) # match craft essence def _craft_essence_empty_check(img1, img2): img1_h = int(img2.shape[1] / img1.shape[1] * img1.shape[0]) img1 = image_process.resize(img1, img2.shape[1], img1_h) img1 = img1[-img2.shape[0]:, ...] v = mean_gray_diff_err(img1, img2) logger.debug('DEBUG value: empty support craft essence check: mean_gray_diff_err = %f' % v) return v < 10 # todo fix bug when empty servant and non-empty craft essence ce_id, t = self._wrap_call_matcher(self.craft_essence_matcher.match, _craft_essence_empty_check, img, self._support_craft_essence_img, range_list) logger.debug('Detected support craft essence ID: %s (used %f sec(s))' % (str(ce_id), t)) ret_list = [SupportServant(x, y) for x, y in zip(svt_id, ce_id)] for i, (y1, y2) in enumerate(range_list): # detect craft essence max break state if ce_id[i] == 0: ret_list[i].craft_essence_max_break = False else: icon = img[y1:y2, CV_SUPPORT_SERVANT_X1:CV_SUPPORT_SERVANT_X2, :] icon = icon[CV_SUPPORT_CRAFT_ESSENCE_MAX_BREAK_Y1:CV_SUPPORT_CRAFT_ESSENCE_MAX_BREAK_Y2, CV_SUPPORT_CRAFT_ESSENCE_MAX_BREAK_X1:CV_SUPPORT_CRAFT_ESSENCE_MAX_BREAK_X2, :] if self._support_craft_essence_img_resized is None: # reduce unnecessary resize ops anchor = image_process.resize(self._support_max_break_img, icon.shape[1], icon.shape[0]) self._support_craft_essence_img_resized = anchor else: anchor = self._support_craft_essence_img_resized # err = mean_gray_diff_err(icon, anchor) hsv_err = image_process.mean_hsv_diff_err(icon, anchor) # logger.debug('DEBUG value: support craft essence max break check: gray_diff_err = %f, hsv_err = %f' % # (err, hsv_err)) ret_list[i].craft_essence_max_break = hsv_err < CV_SUPPORT_CRAFT_ESSENCE_MAX_BREAK_THRESHOLD # skip when support servant is empty if svt_id[i] == 0: continue # detect friend state friend_img = img[y1+CV_SUPPORT_FRIEND_DETECT_Y1:y1+CV_SUPPORT_FRIEND_DETECT_Y2, CV_SUPPORT_FRIEND_DETECT_X1:CV_SUPPORT_FRIEND_DETECT_X2, :] # omit B channel here friend_part_binary = np.greater_equal(np.mean(friend_img[..., :2], 2), CV_SUPPORT_FRIEND_DISCRETE_THRESHOLD) is_friend = np.mean(friend_part_binary) > CV_SUPPORT_FRIEND_DETECT_THRESHOLD ret_list[i].is_friend = is_friend # skill level detection skill_img = img[y1+CV_SUPPORT_SKILL_BOX_OFFSET_Y:y1+CV_SUPPORT_SKILL_BOX_OFFSET_Y+CV_SUPPORT_SKILL_BOX_SIZE, CV_SUPPORT_SKILL_BOX_OFFSET_X1:CV_SUPPORT_SKILL_BOX_OFFSET_X2, :3].copy() gray = np.mean(skill_img, -1) vertical_diff = np.zeros_like(gray, dtype=np.float32) step_size = CV_SUPPORT_SKILL_V_DIFF_STEP_SIZE # pixel offset for computing abs difference vertical_diff[:-step_size, :] = np.abs(gray[:-step_size, :] - gray[step_size:, :]) # just use the first several pixels and last several pixels to determine edge_size = CV_SUPPORT_SKILL_V_DIFF_EDGE_SIZE skills = [] for j in range(3): begin_x = j * (CV_SUPPORT_SKILL_BOX_MARGIN_X + CV_SUPPORT_SKILL_BOX_SIZE) v_diff_current_skill = np.mean(vertical_diff[:, begin_x:begin_x+CV_SUPPORT_SKILL_BOX_SIZE], -1) max_v_diff = np.maximum(np.max(v_diff_current_skill[:edge_size]), np.max(v_diff_current_skill[-edge_size:])) if max_v_diff > CV_SUPPORT_SKILL_V_DIFF_THRESHOLD: # digit recognition, using SSIM metric, split by S (-> 0) and V (-> 255) current_skill_img = skill_img[:, begin_x:begin_x + CV_SUPPORT_SKILL_BOX_SIZE, :] hsv = image_process.rgb_to_hsv(current_skill_img).astype(np.float32) img_digit_part = (1. - hsv[..., 1] / 255.) * (hsv[..., 2] / 255.) img_digit_part = img_digit_part[30:, 3:30] bin_digits = np.greater_equal(img_digit_part, CV_SUPPORT_SKILL_BINARIZATION_THRESHOLD) digit_segments = image_process.split_image(bin_digits) digits = [] for segment in sorted(digit_segments, key=lambda x: (x.max_x + x.min_x)): if 50 < segment.associated_pixels.shape[0] < 150 \ and abs(segment.min_y + segment.max_y - 26) <= 3 \ and segment.max_x - segment.min_x < 14 <= segment.max_y - segment.min_y: digits.append(self._digit_recognizer.recognize(segment.get_image_segment())) if len(digits) == 2: skill_lvl = digits[0] * 10 + digits[1] if skill_lvl != 10: logger.warning(f'Invalid 2 digits skill level: expected 10, but got {skill_lvl}, set to 10') skill_lvl = 10 else: skill_lvl = digits[0] if skill_lvl == 0: logger.warning(f'Invalid 1 digit skill level: expected 1~9, but got {skill_lvl}') skills.append(skill_lvl) else: # skill unavailable skills.append(None) ret_list[i].skill_level = skills logger.info('Detected support servant info: %s' % str(ret_list)) return ret_list