浏览代码

1、删除TMenu中已无任何函数在使用的函数。
2、ConfigManager中所有不对外开放的变量和函数转为私有;
3、完成部分OptionFocus工作,将TFcous中的聚集定位函数抽离进OptionFocus中,TMenu的仍在处理中。

scbc.sat2 5 年之前
父节点
当前提交
cd7e68202f
共有 3 个文件被更改,包括 233 次插入67 次删除
  1. 42 35
      ssat_sdk/MenuTree3/ConfigManager.py
  2. 191 0
      ssat_sdk/MenuTree3/OptionFocus.py
  3. 0 32
      ssat_sdk/MenuTree3/TMenu.py

+ 42 - 35
ssat_sdk/MenuTree3/ConfigManager.py

@@ -7,33 +7,34 @@ from ssat_sdk.MenuTree3.TConfig import TConfig
 # 测试加头文件;
 from TData import CTData
 
-
 g_level = ['First', 'Second', 'Third', 'Fourth', 'Fifth', 'Sixth',
            'Seventh', 'Eighth', 'Ninth', 'Tenth', 'Eleventh', 'Twelfth']
 
 
+# 注意:所有不对外暴露的变量和函数需要私有化,以明确哪些接口和参数是对外的。
+# 这样便于后期维护时,根据对外的变量和函数来做处理。
 class CConfigManager(TConfig, CBaseLog):
     def __init__(self, menuTreeDir, pathManager):
-        self.pathManager = pathManager
-        if self.pathManager is None:
+        self.__pathManager = pathManager
+        if self.__pathManager is None:
             self.error("路径参数错误:None")
         # 状态:False表示路径值失败;
         self.status = False
         # menuTree目录;
-        self.uiTreeDir = menuTreeDir
+        self.__uiTreeDir = menuTreeDir
         # 判断是否为目录;
-        if not os.path.isdir(self.uiTreeDir):
-            self.error("%s 不是menuTree目录" % self.uiTreeDir)
+        if not os.path.isdir(self.__uiTreeDir):
+            self.error("%s 不是menuTree目录" % self.__uiTreeDir)
         # 判断目录是否存在;
-        if not os.path.exists(self.uiTreeDir):
-            self.error("menuTree(%s)目录不存在" % self.uiTreeDir)
+        if not os.path.exists(self.__uiTreeDir):
+            self.error("menuTree(%s)目录不存在" % self.__uiTreeDir)
         # 判断配置文件是否存在;
-        self.configPath = os.path.join(self.uiTreeDir, "menutree.ini")
-        if not os.path.exists(self.configPath):
-            self.error("menutree配置文件不存在:%s" % self.configPath)
+        self.__configPath = os.path.join(self.__uiTreeDir, "menutree.ini")
+        if not os.path.exists(self.__configPath):
+            self.error("menutree配置文件不存在:%s" % self.__configPath)
             self.status = True
         # 初始化父类;
-        TConfig.__init__(self, self.configPath)
+        TConfig.__init__(self, self.__configPath)
 
     # 获取超级密码;
     def getSuperPassword(self):
@@ -69,11 +70,13 @@ class CConfigManager(TConfig, CBaseLog):
 
     # 获取Option的图片配置;
     def __getICONConfig(self, optionName, is_value_sheet=False):
-        paths = self.pathManager.get_option_paths(optionName)
+        # 默认值;
+        def_cfg = {"icon_path": "", "dcfg": {}, "dir_path": ""}
+        paths = self.__pathManager.get_option_paths(optionName)
         # 判断路径节点是否空;
         if paths.__len__() == 0:
-            self.error("当前【%s】的路径节点空" % optionName)
-            return False, {"icon_path": "", "dcfg": {}, "dir_path": ""}
+            self.error("当前【%s】的路径节点空,使用默认的配置值%s" % (optionName, def_cfg))
+            return False, def_cfg
 
         # 获取first parent;
         first_parent = paths[g_level[0]]['parent']
@@ -85,34 +88,37 @@ class CConfigManager(TConfig, CBaseLog):
             cur_level = "value"
 
         # option聚焦的首配图片路径;
-        icon_path = os.path.join(self.uiTreeDir, "icon\\", cur_parent + "." + cur_level + "_" + optionName + ".png")
+        icon_path = os.path.join(self.__uiTreeDir, "icon\\", cur_parent + "." + cur_level + "_" + optionName + ".png")
         # option聚焦的dir首配图片路径;
-        icon_dir_path = os.path.join(self.uiTreeDir, "icon\\" + cur_parent + "." + cur_level + "_" + optionName + ".dir.png")
+        icon_dir_path = os.path.join(self.__uiTreeDir,
+                                     "icon\\" + cur_parent + "." + cur_level + "_" + optionName + ".dir.png")
         # 图片聚焦时的定位参数;
         opc_cfg = self.get_value_dict(cur_level, cur_parent + '.' + optionName)
 
-        last_path = icon_path
         # 首配图片判断是否存在,不存在取用次配图片路径;
         if not os.path.exists(icon_path):
             # 使用次配图片,父级配图;
-            icon_path = os.path.join(self.uiTreeDir, "icon\\" + cur_parent + "." + cur_level + ".png")
-            icon_dir_path = os.path.join(self.uiTreeDir, "icon\\" + cur_parent + "." + cur_level + ".dir.png")
+            self.warn("Option(%s)首配图片不存在:%s" % (optionName, icon_path))
+            icon_path = os.path.join(self.__uiTreeDir, "icon\\" + cur_parent + "." + cur_level + ".png")
+            icon_dir_path = os.path.join(self.__uiTreeDir, "icon\\" + cur_parent + "." + cur_level + ".dir.png")
             opc_cfg = self.get_value_dict(cur_level, cur_parent)
-            self.warn("Option(%s)首配图片不存在:%s,使用次配图:%s" % (optionName, icon_path))
+            self.warn("Option(%s)首配图片不存在,尝试使用次配图(%s):%s,配置%s" % (optionName, cur_parent, icon_path, opc_cfg))
             # 如果次配都不存在,使用顶层配图;
             if not os.path.exists(icon_path):
                 self.warn("Option(%s)次配图片不存在:%s" % (optionName, icon_path))
                 # 使用顶层配图(first parent)
-                icon_path = os.path.join(self.uiTreeDir, "icon\\" + first_parent + "." + cur_level + "_" + optionName +
+                icon_path = os.path.join(self.__uiTreeDir,
+                                         "icon\\" + first_parent + "." + cur_level + "_" + optionName +
                                          ".png")
-                icon_dir_path = os.path.join(self.uiTreeDir, "icon\\" + first_parent + "." + cur_level + "_" + optionName +
+                icon_dir_path = os.path.join(self.__uiTreeDir,
+                                             "icon\\" + first_parent + "." + cur_level + "_" + optionName +
                                              ".dir.png")
                 opc_cfg = self.get_value_dict(cur_level, first_parent)
-
+                self.warn("Option(%s)次配图片不存在,尝试使用顶层配图(%s):%s,配置%s" % (optionName, first_parent, icon_path, opc_cfg))
                 # 如果顶层配图不存在,退出;
                 if not os.path.exists(icon_path):
-                    self.error("%s对应的顶层菜单配图不存在%s" % (optionName, icon_path))
-                    return False, {"icon_path": "", "dcfg": {}, "dir_path": ""}
+                    self.error("%s对应的顶层菜单配图不存在%s,使用默认配置%s" % (optionName, icon_path, def_cfg))
+                    return False, def_cfg
                 # endif
             # endif
         # endif
@@ -133,7 +139,7 @@ class CConfigManager(TConfig, CBaseLog):
     # 获取Option的OCR配置;
     def getOptionOCRConfig(self, optionName):
         ocr_dict = []
-        paths = self.pathManager.get_option_paths(optionName)
+        paths = self.__pathManager.get_option_paths(optionName)
         # 判断路径节点是否空;
         if paths.__len__() == 0:
             self.error("当前【%s】的路径节点空" % optionName)
@@ -142,7 +148,7 @@ class CConfigManager(TConfig, CBaseLog):
         else:
             # 如果状态False,退出;
             if self.status is False:
-                self.warn("配置文件(%s)不存在,%s使用默认的ocr配置", self.configPath, optionName)
+                self.warn("配置文件(%s)不存在,%s使用默认的ocr配置" % (self.__configPath, optionName))
                 ocr_dict = [{"lan": "ChinesePRC+English", "type": 4}, {"lan": "ChinesePRC+English", "type": 253},
                             {"lan": "ChinesePRC+English", "type": 10001}]
             else:
@@ -153,17 +159,17 @@ class CConfigManager(TConfig, CBaseLog):
                     cur_level = g_level[i]
                     # 是否有当前option的ocr配置;
                     if self.has_option(cur_level, optionName + '.ocr'):
-                        self.warn("%s使用自身的ocr配置", optionName)
+                        self.warn("%s使用自身的ocr配置" % optionName)
                         ocr_dict = self.get_dict(self.get_value(cur_level, optionName + '.ocr'))
                         break
                     # 如果option本身没有配置,获取其父节点的配置;
                     if self.has_option(cur_level, cur_parent + '.ocr'):
-                        self.warn("%s使用父节点%s的ocr配置", optionName, cur_parent)
+                        self.warn("%s使用父节点%s的ocr配置" % (optionName, cur_parent))
                         ocr_dict = self.get_dict(self.get_value(cur_level, cur_parent + '.ocr'))
                         break
                     # 如果option父级没有配置,则获取顶层配置(first parent);
                     if self.has_option(cur_level, first_parent + '.ocr'):
-                        self.warn("%s使用顶层节点%s的ocr配置", optionName, first_parent)
+                        self.warn("%s使用顶层节点%s的ocr配置" % (optionName, first_parent))
                         ocr_dict = self.get_dict(self.get_value(cur_level, first_parent + '.ocr'))
                         break
                 # end-for
@@ -171,14 +177,15 @@ class CConfigManager(TConfig, CBaseLog):
         # end-if
         self.info("%s使用的ocr配置=%" % (optionName, ocr_dict))
 
-    # 获取Value的OCR配置;
-    def getValueOCRConfig(self, valueName, paths):
-        pass
+    # 获取ICON源屏幕的分辨率配置值;
+    # 该值用途:由于有些icon是在某些分辨率下截图的,但是同机芯项目可能使用同一套UI,只是分辨率不一样而已。
+    # 所以,根据当初的icon分辨率,可以计算出在别的分辨率下的icon区域大小;
+    def getICONResolutionConfig(self):
+        return self.get_value_dict('Screen', 'shape') if self.has_option('Screen', 'shape') else [1920, 1080]
 
 
 if __name__ == "__main__":
     tData = CTData()
     upath = UITPathManage(tData)
     opc = CConfigManager(r'D:\SAT\resource\MenuTree\RT2851\2851', upath)
-    # print opc.getThresholdDict("factory")
     print opc.getOptionICONConfig("picture")

+ 191 - 0
ssat_sdk/MenuTree3/OptionFocus.py

@@ -0,0 +1,191 @@
+# -*- 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 ConfigManager import CConfigManager
+
+# 测试加头文件;
+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.__feature_detect = 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("获取图片【%s】分辨率成功,使用图片分辨率%s做为当前电视分辨率" % (src_pic, self.__tvResolution))
+            else:
+                self.__tvResolution = [1920, 1080]
+                self.error("获取图片【%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.__feature_detect.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("获取【%s】的icon配置失败,将使用聚集框作为文本框坐标" % curOptionName)
+            return curFocusBox
+
+        dir_path = opc_cfg['dir_path']
+        # 判断方位图是否存在,不存在使用默认聚集框作为文本框;
+        if os.path.exists(dir_path) is False:
+            self.warn("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("读取【%s】失败,将使用聚集框作为文本框坐标" % dir_path)
+            return curFocusBox
+
+        result, focusBox = self.findFocusByIcon(dir_path, curOptionName, isValueSheet)
+        if result is False:
+            self.error("在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 = CConfigManager(r'D:\SAT\resource\MenuTree\RT2851\2851', upath)
+    opfocus = COptionFocus(opcfg)
+
+    result, focusBox = opfocus.findFocusByIcon("", "picture")
+    opfocus.getFocusTextBox("picture", focusBox)

+ 0 - 32
ssat_sdk/MenuTree3/TMenu.py

@@ -108,38 +108,6 @@ class CTMenu():
         self.ccard.takePicture(current_uiPic)
         return current_uiPic
 
-    def getFocusTextBox(self, level, root, focus_box):
-        # 读取ini文件,判断是否有文字方向;
-        if self.tconfig.has_option(level, root + u".text.dir") is True:
-            dict_text = self.tconfig.get_dict(self.tconfig.get_value(level, root + u".text.dir"))
-            # 四个方向的起点坐标计算;
-            left, top, right, bottom = 0, 0, 0, 0
-            if dict_text["dir"] == u"up":
-                left = focus_box[0] + dict_text["x-offset"]
-                bottom = focus_box[1] + dict_text["y-offset"]
-                top = bottom - dict_text["height"]
-                right = left + dict_text["width"]
-            elif dict_text["dir"] == u"down":
-                left = focus_box[0] + dict_text["x-offset"]
-                top = focus_box[3] + dict_text["y-offset"]
-                right = left + dict_text["width"]
-                bottom = top + dict_text["height"]
-            elif dict_text["dir"] == u"left":
-                top = focus_box[1] + dict_text["y-offset"]
-                right = focus_box[0] + dict_text["x-offset"]
-                left = right - dict_text["width"]
-                bottom = top + dict_text["height"]
-            elif dict_text["dir"] == u"right":
-                left = focus_box[2] + dict_text["x-offset"]
-                top = focus_box[1] + dict_text["y-offset"]
-                right = left + dict_text["width"]
-                bottom = top + dict_text["height"]
-            # 返回文本坐标;
-            return [left, top, right, bottom]
-        # endif
-        # 如果没有字段原样返回;
-        return focus_box
-
     def getFocusTextBox3(self, cur_option, focus_box, is_value_sheet=False):
         resutl, opcfg = self.tFocus.getOptionConfig(cur_option, is_value_sheet)
         dcfg = opcfg['dcfg']