# -*- coding:utf-8 -*- from ssat_sdk.picture.RGB import RGBColor from ssat_sdk.picture.color_space import CIEluvCaculator from ssat_sdk.picture.feature_detect import FeatureDetect from ssat_sdk.picture.image_util import * import os import sys import time import numpy as np import cv2 as cv import json from BaseLog import CBaseLog from ExtraData import CExtraData from OptionConfig import COptionConfig from OptionExcel import COptionExcel class COptionFocus(CBaseLog): __rgbColor = RGBColor() __CIE = CIEluvCaculator() __fd = FeatureDetect() def __init__(self, optionConfig): CBaseLog.__init__(self) # CConfigManager对象; self.__optionConfig = optionConfig if self.__optionConfig is None: self.error("configManger对象空") # 当前电视机分辨率(通过截图查看图片大小); self.__tvResolution = None # icon原始分辨率; self.__iconResolution = self.__optionConfig.getICONResolutionConfig() ''' dir.png的用法: 每个dir图片,必定会有一个icon图片。而icon实际上是dir的二次截图,从里抠出来的一块颜色图片。 dir的作用是用来找文本框的,因为有些文字是在icon颜色域外面。 ''' # 已读取过的dir图片对象的icon图片大小记录; # 数据格式及说明: # { # "dir1路径": {"icon_box": ["dir1对应icon,在dir1内的区域坐标"], "width": "dir1图片宽", "height": "dir1图片高"} # "dir2路径": {"icon_box": ["dir2对应icon,在dir2内的区域坐标"], "width": "dir2图片宽", "height": "dir2图片高"} # } self.__dirIconRectDict = {} ''' 函数:通过源图,获取当前电视机的分辨率大小; 参数: 返回: ''' def __getTvResolution(self, src_pic): # 只获取一次; if self.__tvResolution is None or self.__tvResolution.__len__() == 0: src_img = cv.imread(src_pic) if src_img is not None: self.__tvResolution = [src_img.shape[1], src_img.shape[0]] self.info(u"获取图片【%s】分辨率成功,使用图片分辨率%s做为当前电视分辨率" % (src_pic, self.__tvResolution)) else: self.__tvResolution = [1920, 1080] self.error(u"获取图片【%s】分辨率失败,将使用默认分辨率%s做为当前电视分辨率" % (src_pic, self.__tvResolution)) ''' 函数:根据option的配置内容,在指定源图上查找焦点框; 参数: src_pic: 源图路径; opc_cfg: Option的配置数据; 返回:Boolean, [焦点框坐标] ''' def __focusByColor(self, src_pic, opc_cfg): # 将字典参数析出; icon_cfg = opc_cfg['dcfg'] icon_path = opc_cfg['icon_path'] icon_dir_path = opc_cfg['dir_path'] morphology = icon_cfg['morphology'] if 'morphology' in icon_cfg else [] # 读取图片; icon_img = cv.imread(icon_path) if icon_img is None: self.error("读取%s图片失败" % icon_path) return False, None # 获取icon平均bgr值; icon_bgr = COptionFocus.__rgbColor.getAvgBGR(icon_img) # 返回查找结果,失败返回 False, None; 成功返回(焦点的坐标点) True, [l,t,r,b] return COptionFocus.__fd.findCurrentFoucsByColor(src_pic, [], icon_bgr, icon_cfg['offset'], icon_cfg['minPeri'], icon_cfg['maxPeri'], icon_cfg['minArea'], icon_cfg['maxArea'], morphology) ''' 函数:根据Option的icon配置来查找聚集框; 参数: src_pic: 源图; cur_option: Option名称; isValueSheet: false表示查找当前Option的paths配置内容(icon和offset之类), True表示查找当前Option的value配置内容。 即,当前Option是在Excel表的哪个sheet中。 返回:Boolean, [焦点框坐标] ''' def findFocusByIcon(self, src_pic, curOptionName, isValueSheet=False): result, opc_cfg = False, {} if isValueSheet: result, opc_cfg = self.__optionConfig.getValueICONConfig(curOptionName) else: result, opc_cfg = self.__optionConfig.getOptionICONConfig(curOptionName) # 根据源图获取当前电视分辨率; self.__getTvResolution(src_pic) icon_cfg = opc_cfg['dcfg'] # 计算出icon源分辨率与当前电视分辨率比例; resolutionRate = self.__iconResolution[0] / self.__tvResolution[0] if int(resolutionRate) != 1: icon_cfg['minPeri'] = resolutionRate * icon_cfg['minPeri'] icon_cfg['maxPeri'] = resolutionRate * icon_cfg['maxPeri'] icon_cfg['minArea'] = pow(resolutionRate, 2) * icon_cfg['minArea'] icon_cfg['maxArea'] = pow(resolutionRate, 2) * icon_cfg['maxArea'] return self.__focusByColor(src_pic, opc_cfg) ''' 函数:获取焦点框所在区域的文本框坐标; 参数: curOptionName: 当前Option名称; curFocusBox: 当前Option的聚集框区域坐标(由findFocusByIcon所得) isValueSheet: 是否是value表. 返回: 数组[]。文本框坐标 ''' def getFocusTextBox(self, curOptionName, curFocusBox, isValueSheet=False): # 参数校验; if curFocusBox is None or curFocusBox.__len__() == 0: self.error(u"当前聚焦框None或空") return None # 获取配置信息; result, opc_cfg = False, {} if isValueSheet: result, opc_cfg = self.__optionConfig.getValueICONConfig(curOptionName) else: result, opc_cfg = self.__optionConfig.getOptionICONConfig(curOptionName) if result is False: self.warn(u"获取【%s】的icon配置失败,将使用聚集框作为文本框坐标" % curOptionName) return curFocusBox dir_path = opc_cfg['dir_path'] # 判断方位图是否存在,不存在使用默认聚集框作为文本框; if os.path.exists(dir_path) is False: self.warn(u"dir图片%s不存在,将使用聚集框作为文本框坐标" % dir_path) return curFocusBox # 判断该dir是否已读取过(减少文件读写),读取过直接使用记录; if dir_path in self.__dirIconRectDict: # 析出dir的宽高; dirWidth = self.__dirIconRectDict[dir_path]['width'] dirHeight = self.__dirIconRectDict[dir_path]['height'] # 析出dir对应的icon,在dir内的坐标区域; refIconBox = self.__dirIconRectDict[dir_path]['icon_box'] # 计算出dir在原图中实际坐标,即文本区域坐标; x = curFocusBox[0] - refIconBox[0] y = curFocusBox[1] - refIconBox[1] # 返回结果,即文本区域; return [x, y, x + dirWidth, y + dirHeight] # 没有记录,否读取图片并记录; dir_img = cv.imread(dir_path) if dir_img is None: self.error(u"读取【%s】失败,将使用聚集框作为文本框坐标" % dir_path) return curFocusBox result, focusBox = self.findFocusByIcon(dir_path, curOptionName, isValueSheet) if result is False: self.error(u"在dir图片【%s】查找聚集框失败,将使用聚集框作为文本框坐标" % dir_path) return curFocusBox # 记录dir对应的icon等信息, 以备下次使用; self.__dirIconRectDict[dir_path] = {"icon_box": focusBox, "width": dir_img.shape[1], "height": dir_img.shape[0]} # 计算起始坐标点; x, y = curFocusBox[0] - focusBox[0], curFocusBox[1] - focusBox[1] # 返回文本框; return [x, y, x + dir_img.shape[1], y + dir_img.shape[0]] # end-class if __name__ == "__main__": exData = CExtraData() optionExcel = COptionExcel(exData) opcfg = COptionConfig(exData, optionExcel) opfocus = COptionFocus(opcfg) res, Box = opfocus.findFocusByIcon(src_pic="", curOptionName="picture") opfocus.getFocusTextBox("picture", Box)