def __init__(self, need_log: bool = None, engine: typing.Sequence = None, pro_mode: bool = None, *args, **kwargs): """ Init everything. Args here will init the engines too. Read __init__ part in engine.py for details. :param need_log: enable or disable logger :param engine: choose image processing engine, eg: ['feature', 'template'] :param pro_mode: """ # template pic dict, # { pic_name: pic_cv_object } self.template: typing.Dict[str, np.ndarray] = dict() # init logger self.switch_logger(bool(need_log)) # init engine if not engine: # default engine = ['template', 'feature'] self.engine_name_list: typing.List[str] = engine self.engine_list: typing.List[FindItEngine] = list() self.set_engine(engine, *args, **kwargs) # pro mode self.pro_mode = bool(pro_mode) logger.info(f'in pro mode: {self.pro_mode}')
def switch_logger(status: bool): """ enable or disable logger """ if status: logger.enable(LOGGER_FLAG) logger.info('logger up') else: logger.disable(LOGGER_FLAG)
def __init__(self, engine_template_cv_method_name: str = None, engine_template_scale: typing.Sequence = None, engine_template_multi_target_max_threshold: float = None, engine_template_multi_target_distance_threshold: float = None, *_, **__): """ eg: engine_template_cv_method_name -> cv_method_name """ logger.info('engine {} preparing ...'.format(self.get_type())) # cv self.cv_method_name = engine_template_cv_method_name or self.DEFAULT_CV_METHOD_NAME self.cv_method_code = eval(self.cv_method_name) # scale self.scale = engine_template_scale or self.DEFAULT_SCALE # multi target max threshold ( max_val * max_threshold == real threshold ) self.multi_target_max_threshold = engine_template_multi_target_max_threshold or self.DEFAULT_MULTI_TARGET_MAX_THRESHOLD self.multi_target_distance_threshold = engine_template_multi_target_distance_threshold or self.DEFAULT_MULTI_TARGET_DISTANCE_THRESHOLD logger.debug(f'cv method: {self.cv_method_name}') logger.debug(f'scale: {self.scale}') logger.debug( f'multi target max threshold: {self.multi_target_max_threshold}') logger.debug( f'multi target distance threshold: {self.multi_target_distance_threshold}' ) logger.info(f'engine {self.get_type()} loaded')
def __init__(self, engine_sim_interpolation: int = None, *_, **__): logger.info(f'engine {self.get_type()} preparing ...') self.engine_sim_interpolation = engine_sim_interpolation or self.DEFAULT_INTERPOLATION logger.debug(f'interpolation: {self.DEFAULT_INTERPOLATION}') logger.info(f'engine {self.get_type()} loaded')
def find( self, target_pic_name: str, target_pic_path: str = None, target_pic_object: np.ndarray = None, *args, **kwargs, ) -> dict: """ start match :param target_pic_name: eg: 'your_target_picture_1' :param target_pic_path: '/path/to/your/target.png' :param target_pic_object: your_pic_cv_object (loaded by cv2) kwargs here will be used to engine.execute(), which starts with engine_{engine_name}: # ocr engine_ocr_offset: int = None, engine_ocr_deep: bool = None, # template engine_template_mask_pic_object: np.ndarray = None, engine_template_mask_pic_path: str = None, :return: """ # pre assert assert (target_pic_path is not None) or (target_pic_object is not None), "need path or cv object" # load target logger.info("start finding ...") target_pic_object = toolbox.pre_pic(target_pic_path, target_pic_object) if self._need_template(): find_func = self._find_with_template else: find_func = self._find_without_template result = find_func( target_pic_object, target_pic_name=target_pic_name, target_pic_path=target_pic_path, *args, **kwargs, ) return { "target_name": target_pic_name, "target_path": target_pic_path, "data": result, }
def __init__( self, need_log: bool = None, engine: typing.Sequence = None, pro_mode: bool = None, *args, **kwargs, ): """ Init everything. Args here will init the engines too. Read __init__ part in engine.py for details. :param need_log: enable or disable logger :param engine: choose image processing engine, eg: ['feature', 'template'] :param pro_mode: kwargs here will be used to init engine, which starts with engine_{engine_name} : # feature engine_feature_cluster_num: int = None, engine_feature_distance_threshold: float = None, engine_feature_min_hessian: int = None, # ocr engine_ocr_lang: str = None, # sim engine_sim_interpolation: int = None, # template engine_template_cv_method_name: str = None, engine_template_scale: typing.Sequence = None, engine_template_multi_target_max_threshold: float = None, engine_template_multi_target_distance_threshold: float = None, engine_template_compress_rate: float = None, """ # template manager self.template: _TemplateManager = _TemplateManager() # init logger self.switch_logger(bool(need_log)) # init engine if not engine: # default engine = ["template", "feature"] self.engine_name_list: typing.List[str] = engine self.engine_list: typing.List[FindItEngine] = list() self.set_engine(engine, *args, **kwargs) # pro mode self.pro_mode = bool(pro_mode) logger.info(f"in pro mode: {self.pro_mode}")
def __init__(self, engine_ocr_lang: str = None, *_, **__): logger.info(f'engine {self.get_type()} preparing ...') # check language data before execute function, not here. self.engine_ocr_lang = engine_ocr_lang or self.DEFAULT_LANGUAGE self.engine_ocr_tess_data_dir, self.engine_ocr_available_lang_list = tesserocr.get_languages( ) logger.debug(f'target lang: {self.engine_ocr_lang}') logger.debug(f'tess data dir: {self.engine_ocr_tess_data_dir}') logger.debug( f'available language: {self.engine_ocr_available_lang_list}') logger.info(f'engine {self.get_type()} loaded')
def start_server(): logger.info(f"server port: {config.SERVER_PORT}") logger.info(f"pic root dir path: {config.PIC_DIR_PATH}") # check existed assert os.path.exists( config.PIC_DIR_PATH ), f"dir path not existed: {config.PIC_DIR_PATH}" from gevent import monkey, pywsgi monkey.patch_all() server = pywsgi.WSGIServer(("0.0.0.0", int(config.SERVER_PORT)), app) server.serve_forever()
def __init__(self, engine_feature_cluster_num: int = None, engine_feature_distance_threshold: float = None, *_, **__): logger.info('engine {} preparing ...'.format(self.get_type())) # for kmeans calculation self.cluster_num: int = engine_feature_cluster_num or self.DEFAULT_CLUSTER_NUM # for feature matching self.distance_threshold: float = engine_feature_distance_threshold or self.DEFAULT_DISTANCE_THRESHOLD logger.debug('cluster num: {}'.format(self.cluster_num)) logger.debug('distance threshold: {}'.format(self.distance_threshold)) logger.info('engine {} loaded'.format(self.get_type()))
def __init__( self, engine_template_cv_method_name: str = None, engine_template_scale: typing.Sequence = None, engine_template_multi_target_max_threshold: float = None, engine_template_multi_target_distance_threshold: float = None, engine_template_compress_rate: float = None, *_, **__, ): """ eg: engine_template_cv_method_name -> cv_method_name """ logger.info(f"engine {self.get_type()} preparing ...") # cv self.engine_template_cv_method_name = (engine_template_cv_method_name or self.DEFAULT_CV_METHOD_NAME) self.engine_template_cv_method_code = eval( self.engine_template_cv_method_name) # scale self.engine_template_scale = engine_template_scale or self.DEFAULT_SCALE # multi target max threshold ( max_val * max_threshold == real threshold ) self.engine_template_multi_target_max_threshold = ( engine_template_multi_target_max_threshold or self.DEFAULT_MULTI_TARGET_MAX_THRESHOLD) self.engine_template_multi_target_distance_threshold = ( engine_template_multi_target_distance_threshold or self.DEFAULT_MULTI_TARGET_DISTANCE_THRESHOLD) # compression self.engine_template_compress_rate = (engine_template_compress_rate or self.DEFAULT_COMPRESS_RATE) logger.debug(f"cv method: {self.engine_template_cv_method_name}") logger.debug(f"scale: {self.engine_template_scale}") logger.debug( f"multi target max threshold: {self.engine_template_multi_target_max_threshold}" ) logger.debug( f"multi target distance threshold: {self.engine_template_multi_target_distance_threshold}" ) logger.debug(f"compress rate: {self.engine_template_compress_rate}") logger.info(f"engine {self.get_type()} loaded")
def __init__(self, engine_ocr_lang: str = None, *_, **__): logger.info(f"engine {self.get_type()} preparing ...") # check language data before execute function, not here. self.engine_ocr_lang = engine_ocr_lang or self.DEFAULT_LANGUAGE self.engine_ocr_offset = self.DEFAULT_OFFSET self.engine_ocr_deep = self.DEFAULT_DEEP assert findtext, "findtext should be installed if you want to use OCR engine" self._ft = findtext.FindText(lang=engine_ocr_lang) self.engine_ocr_tess_data_dir = self._ft.get_data_home() self.engine_ocr_available_lang_list = self._ft.get_available_lang() logger.debug(f"target lang: {self.engine_ocr_lang}") logger.debug(f"tess data dir: {self.engine_ocr_tess_data_dir}") logger.debug( f"available language: {self.engine_ocr_available_lang_list}") logger.info(f"engine {self.get_type()} loaded")
def execute( self, template_object: np.ndarray, target_object: np.ndarray, engine_template_mask_pic_object: np.ndarray = None, engine_template_mask_pic_path: str = None, *_, **__, ) -> FindItEngineResponse: resp = FindItEngineResponse() resp.append("conf", self.__dict__) # mask if (engine_template_mask_pic_path is not None) or (engine_template_mask_pic_object is not None): logger.info("mask detected") engine_template_mask_pic_object = toolbox.pre_pic( engine_template_mask_pic_path, engine_template_mask_pic_object) # template matching min_val, max_val, min_loc, max_loc, point_list = self._compare_template( template_object, target_object, self.engine_template_scale, engine_template_mask_pic_object, ) # 'target_point' must existed resp.append("target_point", max_loc, important=True) resp.append("target_sim", max_val, important=True) resp.append( "raw", { "min_val": min_val, "max_val": max_val, "min_loc": min_loc, "max_loc": max_loc, "all": point_list, }, ) resp.append("ok", True, important=True) return resp
def __init__(self, engine_feature_cluster_num: int = None, engine_feature_distance_threshold: float = None, engine_feature_min_hessian: int = None, *_, **__): logger.info(f'engine {self.get_type()} preparing ...') # for kmeans calculation self.engine_feature_cluster_num: int = engine_feature_cluster_num or self.DEFAULT_CLUSTER_NUM # for feature matching self.engine_feature_distance_threshold: float = engine_feature_distance_threshold or self.DEFAULT_DISTANCE_THRESHOLD # for determining if a point is a feature point # higher threshold, less points self.engine_feature_min_hessian: int = engine_feature_min_hessian or self.DEFAULT_MIN_HESSIAN logger.debug(f'cluster num: {self.engine_feature_cluster_num}') logger.debug( f'distance threshold: {self.engine_feature_distance_threshold}') logger.debug(f'hessian threshold: {self.engine_feature_min_hessian}') logger.info(f'engine {self.get_type()} loaded')
def load_template(self, pic_name: str, pic_path: str = None, pic_object: np.ndarray = None): """ load template picture :param pic_name: use pic name as result's key, eg: 'your_picture_1' :param pic_path: eg: '../your_picture.png' :param pic_object: eg: your_pic_cv_object) :return: """ assert (pic_path is not None) or (pic_object is not None), "need path or cv object" if pic_object is not None: logger.info("load template from picture object directly ...") self.template.save(pic_name, pic_object) else: logger.info("load template from picture path ...") abs_path = os.path.abspath(pic_path) self.template.save(pic_name, abs_path) logger.info(f"load template [{pic_name}] successfully")
def load_template(self, pic_name: str, pic_path: str = None, pic_object: np.ndarray = None): """ load template picture :param pic_name: use pic name as result's key, eg: 'your_picture_1' :param pic_path: eg: '../your_picture.png' :param pic_object: eg: your_pic_cv_object) :return: """ assert (pic_path is not None) or (pic_object is not None), 'need path or cv object' if pic_object is not None: logger.info('load template from picture object directly ...') self.template[pic_name] = toolbox.load_grey_from_cv2_object( pic_object) else: logger.info('load template from picture path ...') abs_path = os.path.abspath(pic_path) self.template[pic_name] = toolbox.load_grey_from_path(abs_path) logger.info(f'load template [{pic_name}] successfully')
def find(self, target_pic_name: str, target_pic_path: str = None, target_pic_object: np.ndarray = None, *args, **kwargs) -> dict: """ start match :param target_pic_name: eg: 'your_target_picture_1' :param target_pic_path: '/path/to/your/target.png' :param target_pic_object: your_pic_cv_object (loaded by cv2) :return: """ # pre assert assert (target_pic_path is not None) or (target_pic_object is not None), 'need path or cv object' # load target logger.info('start finding ...') target_pic_object = toolbox.pre_pic(target_pic_path, target_pic_object) if self._need_template(): find_func = self._find_with_template else: find_func = self._find_without_template result = find_func(target_pic_object, target_pic_name=target_pic_name, target_pic_path=target_pic_path, *args, **kwargs) return { 'target_name': target_pic_name, 'target_path': target_pic_path, 'data': result }
def execute(self, template_object: np.ndarray, target_object: np.ndarray, mask_pic_object: np.ndarray = None, mask_pic_path: str = None, *_, **__) -> dict: # mask if (mask_pic_path is not None) or (mask_pic_object is not None): logger.info('mask detected') mask_pic_object = toolbox.pre_pic(mask_pic_path, mask_pic_object) # template matching min_val, max_val, min_loc, max_loc, point_list = self._compare_template( template_object, target_object, self.scale, mask_pic_object) # 'target_point' must existed return { 'target_point': max_loc, 'target_sim': max_val, 'conf': { 'engine_template_cv_method_name': self.cv_method_name, 'engine_template_scale': self.scale, 'engine_template_multi_target_max_threshold': self.multi_target_max_threshold, 'engine_template_multi_target_distance_threshold': self.multi_target_distance_threshold }, 'raw': { 'min_val': min_val, 'max_val': max_val, 'min_loc': min_loc, 'max_loc': max_loc, 'all': point_list, } }
def execute(self, template_object: np.ndarray, target_object: np.ndarray, engine_template_mask_pic_object: np.ndarray = None, engine_template_mask_pic_path: str = None, *_, **__) -> FindItEngineResponse: resp = FindItEngineResponse() resp.append('conf', self.__dict__) # mask if (engine_template_mask_pic_path is not None) or (engine_template_mask_pic_object is not None): logger.info('mask detected') engine_template_mask_pic_object = toolbox.pre_pic( engine_template_mask_pic_path, engine_template_mask_pic_object) # template matching min_val, max_val, min_loc, max_loc, point_list = self._compare_template( template_object, target_object, self.engine_template_scale, engine_template_mask_pic_object) # 'target_point' must existed resp.append('target_point', max_loc, important=True) resp.append('target_sim', max_val, important=True) resp.append( 'raw', { 'min_val': min_val, 'max_val': max_val, 'min_loc': min_loc, 'max_loc': max_loc, 'all': point_list, }) resp.append('ok', True, important=True) return resp
def find(self, target_pic_name: str, target_pic_path: str = None, target_pic_object: np.ndarray = None, mark_pic: bool = None, *args, **kwargs): """ start match :param target_pic_name: eg: 'your_target_picture_1' :param target_pic_path: '/path/to/your/target.png' :param target_pic_object: your_pic_cv_object (loaded by cv2) :param mark_pic: enable this, and you will get a picture file with a mark of result :return: """ # pre assert assert self.template, 'template is empty' assert (target_pic_path is not None) or (target_pic_object is not None), 'need path or cv object' # load target logger.info('start finding ...') target_pic_object = toolbox.pre_pic(target_pic_path, target_pic_object) start_time = toolbox.get_timestamp() result = dict() for each_template_name, each_template_object in self.template.items(): logger.debug( 'start analysing: [{}] ...'.format(each_template_name)) current_result = dict() for each_engine in self.engine_list: each_result = each_engine.execute(each_template_object, target_pic_object, *args, **kwargs) # need mark? if mark_pic: target_pic_object_with_mark = toolbox.mark_point( target_pic_object, each_result['target_point'], cover=False) os.makedirs(start_time, exist_ok=True) mark_pic_path = '{}/{}_{}.png'.format( start_time, each_template_name, each_engine.get_type()) cv2.imwrite(mark_pic_path, target_pic_object_with_mark) logger.debug( 'save marked picture to {}'.format(mark_pic_path)) # result filter each_result = self._prune_result(each_result) current_result[each_engine.get_type()] = each_result logger.debug('result for [{}]: {}'.format( each_template_name, json.dumps(current_result))) result[each_template_name] = current_result final_result = { 'target_name': target_pic_name, 'target_path': target_pic_path, 'data': result, } logger.info('result: {}'.format(json.dumps(final_result))) return final_result
def set_engine(self, engine_name_list, *args, **kwargs): logger.info(f'set engine: {engine_name_list}') self.engine_list = [ engine_dict[each](*args, **kwargs) for each in engine_name_list ]
def clear(self): """ reset template, target and result """ self.template = dict() logger.info('findit clear successfully')
def set_engine(self, engine_name_list, *args, **kwargs): logger.info('set engine: {}'.format(engine_name_list)) self.engine_list = [ engine_dict[each](*args, **kwargs) for each in engine_name_list ]