# -*- 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 OptionConfig import COptionConfig # 测试加头文件; from TData import CTData from UIT_PathManage import UITPathManage class COptionFocus(CBaseLog): def __init__(self, configManager): # CConfigManager对象; self.__configManager = configManager if self.__configManager is None: self.error("configManger对象空") self.__rgbColor = RGBColor() self.__CIE = CIEluvCaculator() self.__fd = FeatureDetect() # 当前电视机分辨率(通过截图查看图片大小); self.__tvResolution = None # icon原始分辨率; self.__iconResolution = self.__configManager.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 = self.__rgbColor.getAvgBGR(icon_img) # 返回查找结果,失败返回 False, None; 成功返回(焦点的坐标点) True, [l,t,r,b] return self.__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.__configManager.getValueICONConfig(curOptionName) else: result, opc_cfg = self.__configManager.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): result, opc_cfg = False, {} if isValueSheet: result, opc_cfg = self.__configManager.getValueICONConfig(curOptionName) else: result, opc_cfg = self.__configManager.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__": tData = CTData() upath = UITPathManage(tData) opcfg = COptionConfig(r'D:\SAT\resource\MenuTree\RT2851\2851', upath) opfocus = COptionFocus(opcfg) res, Box = opfocus.findFocusByIcon("", "picture") opfocus.getFocusTextBox("picture", Box)