| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320 | # -*- coding:utf-8 -*-import inspectimport os, sys, time'''用于图片特征提取和定位'''import image_utilimport PreImageJudgeimport cv2 as cvimport numpy as npimport jsonfrom ssat_sdk.sat_environment import *from TST.NetOCR import *from ssat_sdk.ocr_convert import *from color_space import *from line_util import LineUtilfrom ssat_sdk.device_manage import *# 导入枚举;from enum import Enumfrom itertools import chain# from ssat_sdk.device_manage.RedRatHub3 import RedRat3from ssat_sdk.tv_operator import *from ssat_sdk.video_capture import VideoCapture# import ssat_sdk.utils.LoggingUtilfrom ssat_sdk.utils import LoggingUtilfrom ssat_sdk.utils import string_utilfrom ssat_sdk.picture.RGB import RGBColorfrom ssat_sdk.picture.pq_detect import PQDetectpyFileName = os.path.split(__file__)[-1]def get_current_function_name():    return inspect.stack()[1][3]# 效果图形状class IconShape(Enum):    Rectangle = 0   # 矩形;    Circle = 1      # 圆形(包括椭圆)    Polygon = 2     # 多边形class FocusType(Enum):    Border = 0      # 加框;    Coloring = 1    # 着色;    Deform = 2      # 变形;    ColorLine = 3   # 纯色线查找矩形;    ThresholdBinary = 4 # 二值化阀值查找焦点框;    matchTempl = 5  # 模板匹配法查找焦点框;class Direction(Enum):    UnChange = 0    # 区域不变;    TopChange = 1   # 上;    BottomChange = 2  # 下;    LeftChange = 3  # 左;    RightChange = 4 # 右;    ZoomIn = 5      # 放大;    ZoomOut = 6     # 缩小;methods = [cv.TM_CCOEFF, cv.TM_CCOEFF_NORMED, cv.TM_CCORR, cv.TM_CCORR_NORMED, cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]class FeatureDetect():    def __init__(self):        self.className = self.__class__.__name__        self.CIELuv = CIEluvCaculator()        self.OCR = OCRConvert()        self.lineUtil = LineUtil()        # self.redRat3 = RedRat3()        self.redRat3 = TvOperator()        self.vp = VideoCapture()        self.PQ = PQDetect()    '''    检测传入图片的指定区域的线段    :param file:图片文件路径    :param lineMineLen:线段最短长度。 默认 20    :param lineMaxLen:线段最长长度。默认 1000    :param ableArea:指定区域。 默认 整张图片    :return 返回线段数组    '''    def getLinesByFile(self, file, lineMinLen = 20, lineMaxLen = 1000, ableArea=None, threshold1=50, threshold2=100, apertureSize=5):        img = cv.imread(file)        return self.getLines(img, lineMinLen, lineMaxLen, ableArea, threshold1, threshold2, apertureSize)    def getLines(self, img, lineMinLen = 20, lineMaxLen = 1000, ableArea=None, threshold1=50, threshold2=100, apertureSize=5                 , lineThreshold = 200):        targetMat = np.array(img)        if (ableArea <> None):            targetMat = image_util.cutMat(img, ableArea)        grayMat = cv.cvtColor(targetMat, cv.COLOR_BGR2GRAY)        # cv.imshow("gray", grayMat)        edges = cv.Canny(grayMat, threshold1, threshold2, apertureSize=apertureSize)        # cv.imshow("edges",edges)        lines = cv.HoughLinesP(edges, 2, np.pi / 180, lineThreshold)        retLines = []        if lines is None:            return None, None        for line in lines:            x1, y1, x2, y2 = line[0]            # print "line:", x1, y1, x2, y2            # "line rgb:",PreImageJudge.getImgAverageRGB(targetMat, (x1, y1, x2+1, y2+1)), \            # "icon rgb:",PreImageJudge.getAverageRGB(icon)            lineLen = self.lineUtil.caculateLinLen(line[0])            if lineLen > lineMinLen and lineLen < lineMaxLen:                # print "retLine:", line[0]                cv.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)                retLines.append(line[0])        # cv.imshow("getLines", img)        # cv.waitKey(0)        # cv.destroyAllWindows()        return retLines, img    def findRectByFile(self, picPath, type):        img = cv.imread(picPath)        return self.findRectByImg(img, type)    def findRectByImg(self, img, type):        retLines = None        lineImg = None        if (type == "parentLock"):            retLines, lineImg = self.getLines(img, lineThreshold=200)            comLines = self.lineUtil.combineLineList(retLines)            # for line in comLines:            #     print "comLines",line                # cv.line(img, (line[0],line[1]),(line[2],line[3]), (0, 0, 255), 2)            minPoint,maxPoint = self.lineUtil.getLineMMPoint(comLines)            rect = [minPoint[0],minPoint[1], maxPoint[0],maxPoint[1]]            # print rect            # cv.rectangle(img, (minPoint[0], minPoint[1]), (maxPoint[0],maxPoint[1]), (0, 0, 255), 2)            # cv.imshow("comLine", img)            # cv.waitKey(0)            # cv.destroyAllWindows()            return rect        # print retLines        # cv.imwrite(os.path.join(LoggingUtil.getCaseRunLogDirPath(), "lineImg.png"), lineImg)    '''    根据icon,寻找在图片中icon的位置,返回选中区域的特征:文本、文本区域、聚焦区域    :param icon:图标文件路径    :param screen:整张图片文件路径    :param uiDict: 可能出现icon的区域。    例如:    #name的字符串,需为text_area区域显示的文字    {    focus_tv : '{"name":"tv","text_area":[179,210,242,248,"english", 253],"focus_area":[43,128,380,265]}',    focus_av : '{"name":"av","text_area":[180,339,242,381,"english", 253],"focus_area":[43,257,380,395]}',    focus_hdmi1 : '{"name":"hdmi1","text_area":[156,466,269,510,"english", 2],"focus_area":[43,386,380,525]}',    focus_hdmi2 : '{"name":"hdmi2","text_area":[159,599,265,641,"english", 2],"focus_area":[43,517,380,655]}',    focus_usb : '{"name":"media","text_area":[160,730,260,771,"english", 2],"focus_area":[43,648,380,785]}'    }    :param border_wide:四周选择框的厚度    :return 返回文本、文本区域、聚焦区域    '''    def getFocusArea(self, icon, screen, uiDict, border_wide):        # 1 获取焦点框特征        icon_luv= self.calBorderAVGLuvPic(icon, border_wide)        print "icon:", icon_luv        # 2 与可能的聚焦位置进行比较        # print self.focusDict        # 计算直线数最接近区域        target_text_area = None        target_focus_area = None        dLine = 10000        focus_end = "focus_end"        for focus in uiDict:            one_dict = json.loads(uiDict[focus])            area = one_dict["focus_area"]            focus_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus + "_focus.png")            image_util.saveCropPic(screen, focus_img, area)            img_luv = self.calBorderAVGLuvPic(focus_img, border_wide)            # print focus, " ,img_luv:", img_luv            if img_luv is None:                continue            diff = self.CIELuv.getDiffUV(icon_luv, img_luv)            if diff[2] < dLine:                dLine = diff[2]                # print "current dLine:", dLine, area, one_dict["text_area"]                target_focus_area = area                target_text_area = one_dict["text_area"]                focus_end = focus        text_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus_end + ".png")        image_util.saveCropPic(screen, text_img, target_text_area[0:4])        language = target_text_area[4]        ocrType = target_text_area[5]        if len(target_text_area) != 6 or target_text_area[6] == {}:            target_text = self.OCR.getStr(text_img, language, ocrType)        else:            target_text = self.OCR.getStrWithImgProcess(text_img, target_text_area[6], language, ocrType)        # target_text = self.OCR.getStr(text_img, language, ocrType)        print u"getFocusArea,选中区域文字:",target_text        return target_text, target_text_area, target_focus_area    '''    根据icon,寻找在图片中icon的位置    :param icon:选择框图标文件路径    :param screen:整张图片文件路径    :param focusDict: 可能出现icon的区域。    例如:    #name的字符串,需为text_area区域显示的文字    {    'back': [152, 780, 432, 860],    'forgot': [120, 946, 486, 1010],    'gmain': [152, 618, 386, 672]    }    :param border_wide:四周选择框的厚度    :return 聚焦区域    '''    def locateFocusArea(self, icon, screen, focusDict, border_wide):        icon_img = cv.imread(icon)        return self.locateImgFocusArea(icon_img, screen, focusDict, border_wide)    '''        根据icon,寻找在图片中icon的位置        :param icon:选择框图标的cv的mat对象        :param screen:整张图片文件路径        :param focusDict: 可能出现icon的区域。        例如:        #name的字符串,需为text_area区域显示的文字        {        'back': [152, 780, 432, 860],        'forgot': [120, 946, 486, 1010],        'gmain': [152, 618, 386, 672]        }        :param border_wide:四周选择框的厚度        :return 聚焦区域        '''    def locateImgFocusArea(self, icon, screen, focusDict, border_wide):        # 1 获取焦点框特征        icon_luv = self.calBorderAVGLuvImg(icon, border_wide)        # print "icon luv:", icon_luv        # 2 与可能的聚焦位置进行比较,按LUV平均值接近度衡量        focus_area = None        focus_name = None        dLine = 10000        for focus in focusDict:            area = focusDict[focus]            # print "area name:", focus            focus_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), "locateImgFocusArea_focus.png")            image_util.saveCropPic(screen, focus_img, area)            img_luv = self.calBorderAVGLuvPic(focus_img, border_wide)            # print "img_luv:", img_luv,one_dict            if img_luv is None:                continue            diff = self.CIELuv.getDiffUV(icon_luv, img_luv)            # print focus, img_luv,diff            if diff[2] < dLine:                dLine = diff[2]                # print "current dLine:", dLine, area, one_dict["text_area"]                focus_area = area                focus_name = focus        return focus_name, focus_area    '''    计算图片四周边框的颜色平均值,颜色空间Luv    :param pic:图片文件路径    :param wide:四周边框的宽度    :return LUV:四周边框Luv平均值    '''    def calBorderAVGLuvPic(self,pic, wide):        img = cv.imread(pic)        return self.calBorderAVGLuvImg(img, wide)    def calBorderAVGLuvImg(self, img, wide):        luv_img = cv.cvtColor(img, cv.COLOR_BGR2Luv)        height, width, colorDim = luv_img.shape        left_area = [0,0,wide,height]        right_area = [width-wide,0,width,height]        top_area = [wide,0,width-wide,wide]        bottom_area = [wide,height-wide,width-wide,height]        return self.CIELuv.getMAverageLUV(luv_img,[left_area,right_area,top_area,bottom_area])    # Ex interface    '''    描述:寻找图片中符合icon效果图的位置,返回焦点区域的特征:文本、文本区域、聚集区域.    参数:    icon_path: 效果图路径;    screen_path: 要检测焦点框的全屏图路径;    uiDict: ui字典;    示例字典,需为text_area区域显示的文字    {        focus_tv : '{"name":"tv","text_area":[179,210,242,248,"english", 253],"focus_area":[43,128,380,265]}',        focus_av : '{"name":"av","text_area":[180,339,242,381,"english", 253],"focus_area":[43,257,380,395]}',        focus_hdmi1 : '{"name":"hdmi1","text_area":[156,466,269,510,"english", 2],"focus_area":[43,386,380,525]}',        focus_hdmi2 : '{"name":"hdmi2","text_area":[159,599,265,641,"english", 2],"focus_area":[43,517,380,655]}',        focus_usb : '{"name":"media","text_area":[160,730,260,771,"english", 2],"focus_area":[43,648,380,785]}'    }    icon_shape: 效果图形状;    focus_type: 焦点类型;    focus_direction: 焦点变化方向;    border_wide: 焦点框边框大小;    返回值:        None    示例:    注意:    '''    def getFocusAreaEx(self, icon_path, screen_path, uiDict, icon_shape, focus_type, focus_direction, border_wide):        # 整型转枚举;        if type(icon_shape) != type(IconShape.Rectangle):            icon_shape = IconShape(icon_shape)        if type(focus_type) != type(FocusType.Border):            focus_type = FocusType(focus_type)        if type(focus_direction) != type(Direction.ZoomIn):            focus_direction = Direction(focus_direction)        # 矩形效果图;        if icon_shape == IconShape.Rectangle:            return self.getRectangleFocusArea(icon_path, screen_path, uiDict, focus_type, focus_direction, border_wide)        # 圆形效果图;        elif icon_shape == IconShape.Circle:            return self.getCircleFocusArea(icon_path, screen_path, uiDict, focus_type, focus_direction, border_wide)        # 非矩形平行四边形效果图;        elif icon_shape == IconShape.Polygon:             return self.getPolygonFocusArea(icon_path, screen_path, uiDict, focus_type, focus_direction, border_wide)        else:            LoggingUtil.getDebugLogger().info(                pyFileName,                 self.className,                 get_current_function_name(),                 'SDK:icon_shape不存范围内'+icon_shape)            return None, None, None           # 获取矩形的焦点区域;    def getRectangleFocusArea(self, icon_path, screen_path, uiDict, focus_type, focus_direction, border_wide):        # 焦点框(外镶边框)        if focus_type == FocusType.Border:              return self.getBorderRectangleFocusArea(icon_path, screen_path, uiDict, focus_direction, border_wide)        # 区域变色;        elif focus_type == FocusType.Coloring:              return self.getColoringleFocusArea(icon_path, screen_path, uiDict, focus_direction)        # 图形变化;        elif focus_type == FocusType.Deform:              return self.getZoomFocusArea(icon_path, screen_path, uiDict, focus_direction)    # 获取圆形(包含椭圆)的焦点区域;    def getCircleFocusArea(self, icon_path, screen_path, uiDict, focus_type, focus_direction, border_wide):        # 焦点框(外镶边框)        if focus_type == FocusType.Border:              return self.getBorderCircleFocusArea(icon_path, screen_path, uiDict, focus_direction, border_wide)        # 区域变色;        elif focus_type == FocusType.Coloring:              return self.getColoringleFocusArea(icon_path, screen_path, uiDict, focus_direction)        # 图形变化;        elif focus_type == FocusType.Deform:              return self.getZoomFocusArea(icon_path, screen_path, uiDict, focus_direction)    # 多边形的焦点区域;    def getPolygonFocusArea(self, icon_path, screen_path, uiDict, focus_type, focus_direction, border_wide):        # 焦点框(外镶边框)        if focus_type == FocusType.Border:              return self.getBorderRectangleFocusArea(icon_path, screen_path, uiDict, focus_direction, border_wide)        # 区域变色;        elif focus_type == FocusType.Coloring:              return self.getColoringleFocusArea(icon_path, screen_path, uiDict, focus_direction)        # 图形变化;        elif focus_type == FocusType.Deform:              return self.getZoomFocusArea(icon_path, screen_path, uiDict, focus_direction)    '''        # 描述:查找矩形焦点框,选中焦点框的效果为矩形边框外镶一层有色边框。focus_type=0,简述:矩形边框。        # 参数:        # icon_path:焦点框被选中时,外镶一层边框的效果图路径。        # screen_path:需要判断焦点框的电视画面截图。        # uiDict:        # focus_direction:        # border_wide:焦点框被选中时,外镶边框的厚度(像素宽)        # 返回值:        #         # '''    def getBorderRectangleFocusArea(self, icon_path, screen_path, uiDict, focus_direction, border_wide):        # 获取焦点框特征        icon_luv = self.calBorderAVGLuvPic(icon_path, border_wide)               # 计算直线数最接近区域        target_text_area = None        target_focus_area = None        dLine = 10000        focus_end = "focus_end"        for focus in uiDict:            # one_dict = json.loads(uiDict[focus])            one_dict = uiDict[focus]            # print one_dict["focus_area"]            # diff = 11            area = one_dict["focus_area"]            # area = [one_dict["focus_area"][0] - diff,one_dict["focus_area"][1] - diff,one_dict["focus_area"][2] + diff,one_dict["focus_area"][3] + diff]            # zoomin;            # print area            focus_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus + "_focus.png")            image_util.saveCropPic(screen_path, focus_img, area)            img_luv = self.calBorderAVGLuvPic(focus_img, border_wide)            # print focus, " ,img_luv:", img_luv            if img_luv is None:                continue            diff = self.CIELuv.getDiffUV(icon_luv, img_luv)            if diff[2] < dLine:                dLine = diff[2]                # print "current dLine:", dLine, area, one_dict["text_area"]                target_focus_area = area                target_text_area = one_dict["text_area"]                focus_end = focus        #end for                try:            # 识别焦点区域文字;            target_text = None            if list(target_text_area[0:4]) != list([-1,-1,-1,-1]):                text_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus_end + ".png")                image_util.saveCropPic(screen_path, text_img, target_text_area[0:4])                language = target_text_area[4]                ocrType = target_text_area[5]                if len(target_text_area) != 6 or target_text_area[6] == {}:                    target_text = self.OCR.getStr(text_img, language, ocrType)                else:                    target_text = self.OCR.getStrWithImgProcess(text_img, target_text_area[6], language, ocrType)                # target_text = self.OCR.getStr(text_img, language, ocrType)                print u"getFocusArea,选中区域文字:",target_text            # 返回;            return target_text, target_text_area, target_focus_area        except Exception, e:            LoggingUtil.getDebugLogger().info(                pyFileName,                 self.className,                 get_current_function_name(),                 'SDK:OCR识别异常'+e)            return None,None,None    # 圆形边框;    def getBorderCircleFocusArea(self, icon_path, screen_path, uiDict, focus_direction, border_wide):        return None,None,None    # 多边形边框;    def getBorderPolygonFocusArea(self, icon_path, screen_path, uiDict, focus_direction, border_wide):        return None,None,None    '''        # 描述:查找焦点框(不区分形状),选中效果为焦点框背景色变化成其他颜色。focus_type=1,简述:区域着色        # 参数:        # icon_path:焦点框被选中时,背景变色的效果图路径。        # screen_path:需要判断焦点框的电视画面截图。        # uiDict:        # focus_direction:        # 返回值:        #         # '''    def getColoringleFocusArea(self, icon_path, screen_path, uiDict, focus_direction):        # 获取效果图的luv平均值;        imgColoring = cv.imread(icon_path)        luvColoring = self.CIELuv.getAverageLUV(imgColoring)        # 遍历字典中所有区域截图,计算luv值;        luvNoraml = None        # 目标文本区域;        target_text_area = None        # 目标焦点区域;        target_focus_area = None        # 默认最大值;        dLine = 10000        focus_end = "focus_end"        for focus in uiDict:            #正常图片;            # print u'name=',focus            one_dict = uiDict[focus]            normalArea = one_dict["focus_area"]            focus_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus + "_focus.png")            image_util.saveCropPic(screen_path, focus_img, normalArea)            luvNoraml = self.CIELuv.getAverageLUV(cv.imread(focus_img))            if luvNoraml is None:                continue            # print u'normalArea=',normalArea                        # 计算相差;            diff = self.CIELuv.getDiffUV(luvColoring, luvNoraml)            if diff[2] < dLine:                dLine = diff[2]                target_focus_area = normalArea                target_text_area = one_dict["text_area"]                focus_end = focus        try:            # 识别焦点区域文字;            target_text = None            text_img_path = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus_end + ".png")            if list(target_text_area[0:4]) != list([-1,-1,-1,-1]):                image_util.saveCropPic(screen_path, text_img_path, target_text_area[0:4])                language = target_text_area[4]                ocrType = target_text_area[5]                if len(target_text_area) != 6 or target_text_area[6] == {}:                    target_text = self.OCR.getStr(text_img_path, language, ocrType)                else:                    target_text = self.OCR.getStrWithImgProcess(text_img_path, target_text_area[6], language, ocrType)                                # target_text = self.OCR.getStr(text_img_path, language, ocrType)                # print u"getFocusArea,选中区域文字:",target_text            # 返回文本内容、文本区域、焦点区域;            return target_text, target_text_area, target_focus_area         except Exception, e:            LoggingUtil.getDebugLogger().info(                pyFileName,                 self.className,                 get_current_function_name(),                 'SDK:OCR识别异常'+e)            return None,None,None    '''        # 描述:获取两区域的缩放率         # 参数:        # normalArea:区域坐标值,如[0,0,100,100]        # imgZoomin:图像对象,使用cv.imread('path')获取的数组;        # isZoomin:缩放率是放大率,还是缩小率, True放大率,False缩小率.        #         # 返回值:        #   返回浮点值,缩放率scale        # 示例:        #         # 注意:        #         # '''    def getZoomScale(self, normalArea, imgZoomin, isZoomin = False):        scale = 0.000        if imgZoomin is None:            return scale        if isZoomin == True:            scale = float(imgZoomin.shape[1]) / (normalArea[2] - normalArea[0])        else:            scale = float(normalArea[2] - normalArea[0]) / imgZoomin.shape[1]        # 返回缩放率;        return scale        '''        # 描述:查找焦点框,选中焦点框的效果为放大后的焦点框,focus_type=2        # 参数:        # icon_path:        # screen_path:        # uiDict:        # focus_direction:        #         # 返回值:        #         #         # 注意:        #         #         # '''    def getZoomFocusArea(self, icon_path, screen_path, uiDict, focus_direction):        # 获取放大的图像;        imgZoomin = cv.imread(icon_path)        # 获取第一个正常图标区域;        normalArea = uiDict.values()[1]["focus_area"]        # 计算放大率;        zoominScale = self.getZoomScale(normalArea, imgZoomin, True)                       # 遍历所有的区域,计算接近值;        # 放大的矩形区域;        zoominArea = None        # 目标文本区域;        target_text_area = None        # 目标焦点区域;        target_focus_area = None        # 默认最大值;        dLine = 10000        focus_end = "focus_end"        # 矩形中心坐标点;        cx,cy = None, None        # 矩形宽高;        width, height = None, None        for focus in uiDict:            #正常图片;            # print u'name=',focus            one_dict = uiDict[focus]            normalArea = one_dict["focus_area"]            focus_img = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus + "_focus.png")            image_util.saveCropPic(screen_path, focus_img, normalArea)            img_luv = self.CIELuv.getAverageLUV(cv.imread(focus_img))            if img_luv is None:                continue            # print u'normalArea=',normalArea            # 中心点位置;            cx,cy = normalArea[0]+(normalArea[2] - normalArea[0])/2,  normalArea[1]+(normalArea[3] - normalArea[1])/2            # print u'中心点位置',cx,cy            # 宽高;            width, height = (normalArea[2] - normalArea[0])/2,  (normalArea[3] - normalArea[1])/2            # print u'宽,高',width, height                        # 计算放大的区域值;            zoominArea = [int(cx-width*zoominScale), int(cy-height*zoominScale), int(cx+width*zoominScale), int(cy+height*zoominScale)]            # print u'zoomin=',zoominArea            #保存放大区域截图;            focus_img_path = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus + "_zoomin.png")            image_util.saveCropPic(screen_path, focus_img_path, zoominArea)            focus_img = cv.imread(focus_img_path)            if focus_img is None:                # print u'focus_img is None,路径:',focus_img_path                LoggingUtil.getDebugLogger().info(                pyFileName,                 self.className,                 get_current_function_name(),                 'SDK:focus_img is None,路径:'+focus_img_path)                continue            imgZoomin_luv = self.CIELuv.getAverageLUV(focus_img)                        # 计算相差;            diff = self.CIELuv.getDiffUV(imgZoomin_luv, img_luv)            if diff[2] < dLine:                dLine = diff[2]                target_focus_area = normalArea                target_text_area = one_dict["text_area"]                focus_end = focus        try:            # 识别焦点区域文字;            target_text = None            text_img_path = os.path.join(LoggingUtil.getCaseRunLogDirPath(), focus_end + ".png")            if list(target_text_area[0:4]) != list([-1,-1,-1,-1]):                image_util.saveCropPic(screen_path, text_img_path, target_text_area[0:4])                language = target_text_area[4]                ocrType = target_text_area[5]                if len(target_text_area) != 6 or target_text_area[6] == {}:                    target_text = self.OCR.getStr(text_img_path, language, ocrType)                else:                    target_text = self.OCR.getStrWithImgProcess(text_img_path, target_text_area[6], language, ocrType)                                # target_text = self.OCR.getStr(text_img_path, language, ocrType)            # print u"getFocusArea,选中区域文字:",target_text            # 返回文本内容、文本区域、焦点区域;            return target_text, target_text_area, target_focus_area         except Exception, e:            # print u'except',e            LoggingUtil.getDebugLogger().info(                pyFileName,                 self.className,                 get_current_function_name(),                 'SDK:OCR识别异常'+e)            return None,None,None    '''        # 描述:查找矩形焦点框,选中焦点框的效果为焦点背景色变成纯色。focus_type=3。        # 参数:        # dict:        #        # 返回值:        # '''    def autoRecognitionFocusArea(self, dict, percent = 0.9):        if dict is None:            print u'autoRecognitionFocusArea:dict is None'            return None, None, None        # 路径;        imgPath = dict["shootPicPath"]        zoneArea = dict["zone_area"]        refFocusArea = dict["focus_area"]        refTextArea = list(dict["text_area"])        colorArea = dict["color_area"]        imgHome = cv.imread(imgPath)        if imgHome is None:            print u'autoRecognitionFocusArea:imgHome is None'            return None, None, None         # colorArea中心点,用于取色;        cx,cy = colorArea[0] + int(colorArea[2] - colorArea[0])/2, colorArea[1] + int(colorArea[3] - colorArea[1])/2        # 背景色;        # bgColor = imgHome[cy][cx]        # call        return self.__autoRecognitionFocusArea(            dict["currentPicPath"],             imgHome[cy][cx],             zoneArea,             refFocusArea,            refTextArea,            percent            )    '''        # 描述:        # 参数:        # imgPath:要检测焦点框的图片路径。如:"D:\\Home.png"        # focusBGColor:选中的焦点框的着色值,bgr格式。如:[122,122,122]        # zoneArea:焦点框所在区域范围坐标,坐标点相对于imgPath图片。如(x1,y1,x2,y2):[10,10,50,50]        # focusWidth:选中的焦点框宽度。        # focusHeight:选中的焦点框高度。        # textArea:文本区域在焦点框中的坐标。        # language:语言        # orcType:        #        # 返回值:        #         # '''    def __autoRecognitionFocusArea(self, imgPath, focusBGColor, zoneArea, refFocusArea, refTextArea, percent = 0.9):        imgHome = cv.imread(imgPath)        # 水平、垂直        hLine1, hLine2 = [],[]        # 宽、高;        focusWidth, focusHeight = refFocusArea[2]-refFocusArea[0],refFocusArea[3]-refFocusArea[1]        # 是否找到        bhLine1, bhLine2 = False,False        if imgHome is None:            # print u'__autoRecognitionFocusArea:imgHome is None'            LoggingUtil.getDebugLogger().info(                pyFileName,                 self.className,                 get_current_function_name(),                 'SDK:图片对象空,可能路径不正确')            return None, None, None        else:            # 第一行;            for y in range(zoneArea[1], zoneArea[3]):                for x in range(zoneArea[0], zoneArea[2]):                    if bhLine1 == False:                        # if list(imgHome[y][x]) == list(focusBGColor):                        if self.CIELuv.isColorSimilar(imgHome[y][x],focusBGColor) == True:                            hLine1.append([x,y])                    #end if                #end for                # 判断本线是否符合要求;                if bhLine1 == False:                    count = len(hLine1)                    if float(count)/focusWidth > percent:                        bhLine1 = True                    else:                        hLine1 = []            #end for            if len(hLine1) == 0:                # print u'__autoRecognitionFocusArea: 未找到第一行,长度为0'                LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:未找到第一行,长度为0')                return None, None, None            #最后一行,倒查;            zoneArea = [hLine1[0][0]-10, hLine1[0][1], hLine1[0][0] + focusWidth, hLine1[0][1] + focusHeight]            print u'zoneArea=',zoneArea            for y in range(zoneArea[3], zoneArea[1],-1):                for x in range(zoneArea[0], zoneArea[2]):                    if bhLine2 == False:                        # if list(imgHome[y][x]) == list(focusBGColor):                        if self.CIELuv.isColorSimilar(imgHome[y][x],focusBGColor) == True:                            hLine2.append([x,y])                    #end if                #end for                 # 判断本线是否符合要求;                if bhLine2 == False:                    count = len(hLine2)                    if float(count)/focusWidth > percent:                        bhLine2 = True                    else:                        hLine2 = []            #end for            if len(hLine2) == 0:                # print u'__autoRecognitionFocusArea: 未找到最后一行,长度为0'                LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:未找到最后一行,长度为0')                return None, None, None            # 焦点区域;            focusArea = [hLine1[0][0], hLine1[0][1], hLine2[-1][0], hLine2[-1][1]]            # 查找文本区域;            realTextArea = self.findCurrentFocusTextBox(focusArea, refFocusArea, refTextArea[0:4])            if realTextArea is None:                return None,None,focusArea            # ocr识别文本;            target_text = self.getCurrentFocusText(imgPath, realTextArea, refTextArea[4:])            # 返回结果;            return target_text, realTextArea, focusArea    '''    Tenengrad梯度方法利用Sobel算子分别计算水平和垂直方向的梯度,同一场景下梯度值越高,图像越清晰。    以下是具体实现,这里衡量的指标是经过Sobel算子处理后的图像的平均灰度值,值越大,代表图像越清晰。    :param 图片路径    :return float, 值越大,代表清晰度越高    '''    def detSharpTenengrad(self, pic_path):        return self.PQ.detSharpTenengrad(pic_path)    '''    采用Laplacian梯度方法检测清晰度    :param 图片路径    :return float, 值越大,代表清晰度越高    '''    def detSharpLaplacian(self, pic_path):        return self.PQ.detSharpLaplacian(pic_path)    '''    img:opencv图像对象,BGR颜色空间    '''    def detImgSharpLaplacian(self, img):        return self.PQ.detImgSharpLaplacian(img)    '''    采用方差(Variance)方法检测清晰度。    方差是概率论中用来考察一组离散数据和其期望(即数据的均值)之间的离散(偏离)成都的度量方法。    方差较大,表示这一组数据之间的偏差就较大,组内的数据有的较大,有的较小,分布不均衡;    方差较小,表示这一组数据之间的偏差较小,组内的数据之间分布平均,大小相近。    :param 图片路径    :return float, 值越大,代表清晰度越高    '''    def detSharpVariance(self, pic_path):        return self.PQ.detSharpVariance(pic_path)    '''        # 描述:获取满足指定周长、面积范围的灰度二值化轮廓;        # 参数:        # bInside:使用内轮廓        # tvShotPath:图片路径        # cropArea:裁剪区域, 如:[left,top,right,bottom]        # grayVal:灰度值;        # maxGrayVal:最大灰度值        # minPeri: 最小周长;        # maxPeri: 最大周长;        # minArea: 最小面积;        # maxArea: 最大面积;        # find_1st: 是否只返回满足条件的第一个值        #         # 返回:返回满足指定周长、面积范围的一个或多个轮廓坐标,坐标值如:[left,top,right,bottom];        #         # '''    def getGrayBinaryContour(self, tvShotPath, cropArea, grayVal, maxGrayVal, bInside, minPeri, maxPeri, minArea, maxArea, find_1st = True):        contourRect = [0,0,0,0]#结果:x1,y1,x2,y2;        img_binary = self.getBinaryImage(tvShotPath, cropArea, grayVal, maxGrayVal)       # 获取二值化图像的轮廓;        area, perimeter = 0.0, 0.0        if bInside == False:#外轮廓            contours = cv.findContours(img_binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[1]        else:#内轮廓            contours = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)[1]                # 是否查找最大轮廓;        bFindMaxContour = False        if minPeri == maxPeri and minArea == maxArea:            bFindMaxContour = True        listBox = []        maxContour = None #最大轮廓;        tempArea = 0        # 过滤掉不符合要求的轮廓;        x, y, w, h,result = 0,0,0,0,False        for cnt in contours:            # 面积;            area = cv.contourArea(cnt)            # 周长;            perimeter = cv.arcLength(cnt, True)            if bFindMaxContour == True:                # 获取最大轮廓;                if tempArea < area:                    tempArea = area                    maxContour = cnt            else:                # print area,perimeter                # 获取满足条件的值;                if area >= minArea and area <= maxArea and perimeter >= minPeri and perimeter <= maxPeri:                    # 直边矩形,(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高;                    x, y, w, h = cv.boundingRect(cnt)                    # print u'boundingRect=',x,y,w,h                    LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:当前找到的轮廓='+str((x,y,w,h)))                    # 在区域内截图判断;                    if cropArea is not None:                        x = x + cropArea[0]                        y = y + cropArea[1]                    contourRect = [x,y,x+w,y+h]                    # 如果只找第一个;                    if find_1st == True:                        result = True                        break                    # 多个;                    listBox.append(contourRect)                #endif        #endfor        if bFindMaxContour == True:            # 最大轮廓的矩形坐标;            x, y, w, h = cv.boundingRect(maxContour)            # 在区域内截图判断;            if cropArea is not None:                x = x + cropArea[0]                y = y + cropArea[1]            contourRect = [x,y,x+w,y+h]        if bFindMaxContour == True:            return contourRect        # 只返回满足条件的第一个值;        if find_1st == True:            return contourRect if result == True else None        else:            return listBox    #end    # 区域=焦点=图片;    def isNoneFocustArea(self,dict):         # 解析参数;        Coordinate = dict["ZoneCoordinate"]# 区域坐标;        if len(dict["FocusList"]) == 0:            return False        FocustArea = dict["FocusList"][0]["focus_area"]        if list(Coordinate) != list(FocustArea):            return False        return True    '''        # 描述:获取满足指定周长、面积范围的灰度二值化轮廓;        # 参数:        # bInside:使用内轮廓        # tvShotPath:图片路径        # cropArea:裁剪区域, 如:[left,top,right,bottom]        # maxGrayVal:最大灰度值        # minPeri: 最小周长;        # maxPeri: 最大周长;        # minArea: 最小面积;        # maxArea: 最大面积;        # find_1st: 是否只返回满足条件的第一个值        #        # 注意:当minPeri == maxPeri and minArea == maxArea时,只求最大的轮廓坐标;        #        # 返回:返回满足指定周长、面积范围的一个或多个轮廓坐标,坐标值如:[left,top,right,bottom];        #         # '''    def getOTSUBinaryContour(self, tvShotPath, cropArea, maxGrayVal, bInside, minPeri, maxPeri, minArea, maxArea, find_1st = True):        contourRect = [0,0,0,0]#结果:x1,y1,x2,y2;        img_binary = self.getBinaryImage(tvShotPath, cropArea, 0, maxGrayVal, thresholdType=1)       # 获取二值化图像的轮廓;        area, perimeter = 0.0, 0.0        if bInside == False:#外轮廓            contours = cv.findContours(img_binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[1]        else:#内轮廓            contours = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)[1]                # 是否查找最大轮廓;        bFindMaxContour = False        if minPeri == maxPeri and minArea == maxArea:            bFindMaxContour = True        listBox = []        maxContour = None #最大轮廓;        tempArea = 0        # 过滤掉不符合要求的轮廓;        x, y, w, h,result = 0,0,0,0,False        for cnt in contours:            # 面积;            area = cv.contourArea(cnt)            # 周长;            perimeter = cv.arcLength(cnt, True)            if bFindMaxContour == True:                # 获取最大轮廓;                if tempArea < area:                    tempArea = area                    maxContour = cnt            else:                # print area,perimeter                # 获取满足条件的值;                if area >= minArea and area <= maxArea and perimeter >= minPeri and perimeter <= maxPeri:                    # 直边矩形,(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高;                    x, y, w, h = cv.boundingRect(cnt)                    # print u'boundingRect=',x,y,w,h                    LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:当前找到的轮廓='+str((x,y,w,h)))                    # 在区域内截图判断;                    if cropArea is not None:                        x = x + cropArea[0]                        y = y + cropArea[1]                    contourRect = [x,y,x+w,y+h]                    # 如果只找第一个;                    if find_1st == True:                        result = True                        break                    # 多个;                    listBox.append(contourRect)                #endif        #endfor        if bFindMaxContour == True:            # 最大轮廓的矩形坐标;            x, y, w, h = cv.boundingRect(maxContour)            # 在区域内截图判断;            if cropArea is not None:                x = x + cropArea[0]                y = y + cropArea[1]            contourRect = [x,y,x+w,y+h]        if bFindMaxContour == True:            return contourRect        # 只返回满足条件的第一个值;        if find_1st == True:            return contourRect if result == True else None        else:            return listBox    #end    '''    # focus_type = 4;    # dict:区域信息;    # bInside:是否使用内轮廓;    '''    def getSelectFocusArea(self, dict):        if self.isNoneFocustArea(dict) == True:            return None,None,dict["ZoneCoordinate"]                # 获取轮廓;        try:            bInside = dict["InsideContours"]# 是否使用内轮廓;        except:            bInside = False        contourRect = self.getGrayBinaryContour(            dict["TVShotPath"],            dict["ZoneCoordinate"],            dict["ZoneThreshold"],            dict["ZoneMaxThreshold"],            bInside,            dict["RenderingsMinGirth"],            dict["RenderingsMaxGirth"],            dict["RenderingsMinArea"],            dict["RenderingsMaxArea"])        if contourRect == None:            # print u'没有找到轮廓区域'            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK-ERROR:没有找到轮廓区域')            return None,None,None        #endif        # 遍历区域,找到内包含的区域;        x1,y1,x2,y2,result = 0,0,0,0,False        allFocus = dict["FocusList"]        for focus in allFocus:            x1,y1,x2,y2 = focus["focus_area"][0],focus["focus_area"][1],focus["focus_area"][2],focus["focus_area"][3]            #是否在效果图的轮廓内            if x1 >= contourRect[0] and y1 >= contourRect[1] and x2 <= contourRect[2] and y2 <= contourRect[3]:                result = True                break        #endfor        if result == False:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:已找到焦点轮廓,但该轮廓未包含任何focus_area在内')            return None,None,None        # 获取当前焦点文本;        target_text = self.getCurrentFocusText(dict["TVShotPath"], focus["text_area"][0:4], focus["text_area"][4:])        return target_text, focus["text_area"][0:4], focus["focus_area"]    #end    # 是否进入到指定UI界面;    def isEntryUI(self, dict):        try:            bInside = dict["InsideContours"]# 是否使用内轮廓;        except:            bInside = False        contourRect = self.getGrayBinaryContour(            dict["TVShotPath"],            dict["ZoneCoordinate"],            dict["ZoneThreshold"],            dict["ZoneMaxThreshold"],            bInside,            dict["RenderingsMinGirth"],            dict["RenderingsMaxGirth"],            dict["RenderingsMinArea"],            dict["RenderingsMaxArea"])        # contourRect = self.getGrayBinaryContour(dict)        if contourRect == None:            # print u'isEntryUI:没有找到轮廓区域'            LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:没有找到轮廓区域')            return False        #endif                return True    #end    '''    # 描述:获取模板匹配度最高的目标。    # 参数:    # imgObj:图像对象,由cv2.imread()读取    # templObj:图库对象,由cv2.imread()读取    # 图像对象可以是RGB格式,也可以是GRAY格式,也可以是二值化后的图像对象;    '''    def templMatch(self, imgObj, templObj, setting = {'method':5, 'colorType':0, 'thresholdVal':0, 'thresholdMaxVal':255, 'matchVal':0.90 }):        # 参数判断;        if imgObj is None or templObj is None:            # print u'图像对象空'            LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:图像对象空')            return None,None        if setting["colorType"] == 1: # gray模式;            imgObj = cv.cvtColor(imgObj, cv.COLOR_BGR2GRAY)            templObj = cv.cvtColor(templObj, cv.COLOR_BGR2GRAY)        elif setting["colorType"] == 2: # threshold模式;            # 转成灰阶图;            imgObj = cv.cvtColor(imgObj, cv.COLOR_BGR2GRAY)            templObj = cv.cvtColor(templObj, cv.COLOR_BGR2GRAY)            # 将灰阶转成二值化图像;            imgObj = cv.threshold(imgObj, setting["thresholdVal"], setting["thresholdMaxVal"], cv.THRESH_BINARY)[1]            templObj = cv.threshold(templObj, setting["thresholdVal"], setting["thresholdMaxVal"], cv.THRESH_BINARY)[1]        # 模板匹配;        retVal = cv.matchTemplate(imgObj, templObj, setting["method"])        # 最小最大值;        min_val, max_val, min_loc, max_loc = cv.minMaxLoc(retVal)        if setting["method"] == cv.TM_SQDIFF_NORMED or setting["method"] == cv.TM_SQDIFF:            return min_val, min_loc        else:            return max_val, max_loc        '''    # 描述:模板有多个匹配目标    # imgObj:图像对象,由cv2.imread()读取    # templObj:图库对象,由cv2.imread()读取    # 图像对象可以是RGB格式,也可以是GRAY格式,也可以是二值化后的图像对象;    # '''    def templMultiMatch(self, imgObj, templObj, setting = {'method':5, 'colorType':0, 'thresholdVal':0, 'thresholdMaxVal':255, 'matchVal':0.90 }):        # 参数判断;        if imgObj is None or templObj is None:            # print u'图像对象空'            LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:图像对象空')            return None        w,h = templObj.shape[::-1]        if setting["colorType"] == 1: # gray模式;            imgObj = cv.cvtColor(imgObj, cv.COLOR_BGR2GRAY)            templObj = cv.cvtColor(templObj, cv.COLOR_BGR2GRAY)        elif setting["colorType"] == 2: # threshold模式;            # 转成灰阶图;            imgObj = cv.cvtColor(imgObj, cv.COLOR_BGR2GRAY)            templObj = cv.cvtColor(templObj, cv.COLOR_BGR2GRAY)            # 将灰阶转成二值化图像;            imgObj = cv.threshold(imgObj, setting["thresholdVal"], setting["thresholdMaxVal"], cv.THRESH_BINARY)[1]            templObj = cv.threshold(templObj, setting["thresholdVal"], setting["thresholdMaxVal"], cv.THRESH_BINARY)[1]        listVal = []        # 模板匹配;        retVal = cv.matchTemplate(imgObj, templObj, setting["method"])        # 匹配的阀值        if setting["method"] == cv.TM_SQDIFF_NORMED or setting["method"] == cv.TM_SQDIFF:            matchVal = 1 - setting["matchVal"]        else:            matchVal = setting["matchVal"]        loc = np.where(retVal > matchVal)        # 如果匹配的多个目标是横排序的,过滤掉重影框;        listTup = sorted(zip(*loc[::-1]))        # 第一个矩形;        x1,y1 = listTup[-1][0]-10, listTup[-1][1]-10        x2,y2 = x1+w+20, y1+h+20        # 中心点是否在矩形内;        bInRect = False        for i in range(len(listTup)-1, -1, -1):             pt = (listTup[i][0],listTup[i][1])            x,y = pt[0]+w/2,pt[1]+h/2            if x > x1 and x < x2 and y > y1 and y < y2:                if bInRect == False:                    bInRect = True                else:                    listTup.pop(i)            else:                # print u'外坐标:',pt                x1,y1 = pt[0]-10,pt[1]-10                x2,y2 = x1+w+10, y1+h+10        # 如果匹配的多个目标是坚排序的,过滤掉重影框;        bInRect = False        listTup = sorted(listTup, key=lambda x:x[1])        # 第一个矩形;        x1,y1 = listTup[0][0]-10, listTup[0][1]-10        x2,y2 = x1+w+20, y1+h+20        for pt in listTup:             x,y = pt[0]+w/2,pt[1]+h/2            if x > x1 and x < x2 and y > y1 and y < y2:                if bInRect == False:                    bInRect = True                    listVal.append([pt[0],pt[1],pt[0]+w,pt[1]+h])            else:                # 中心点不在矩形内,切换矩形;                x1,y1 = pt[0]-10,pt[1]-10                x2,y2 = x1+w+10, y1+h+10                 listVal.append([pt[0],pt[1],pt[0]+w,pt[1]+h])                # 返回多个目标的坐标值;        return listVal    '''    # 获取图库目录图像;    # dir:图库路径    # extlist:保留的后缀文件,都是图像格式。    '''    def getGallery(self, dir, extlist = ['.png','.bmp','.jpg','jpeg','.tiff']):        tmplist = []        dir = unicode(dir)        if os.path.exists(unicode(dir)) == True:            # 读取图库路径里的所有图片;            list = os.listdir(dir)            # 后缀、路径;            path, ext = "", ""            # 遍历,过滤掉文件夹和非图像文件;            for file in list:                path = os.path.join(dir, file)                if os.path.isfile(path):                    ext = os.path.splitext(path)[1]  # 获取文件后缀 [0]获取的是除了文件名以外的内容                    if ext in extlist:                        tmplist.append(path)            #end for        else:            # print u'路径异常',dir            LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:路径异常')        return tmplist    '''    # 描述:模板匹配,只返回图库中匹配值符合的一个或多个模板的相关数据。    # srceenImgPath:原图路径,即TV截图;    # ZoneCoordinate:要匹配的区域    # galleryDir: 图库路径;    # setting: 设定参数    #   method -> [cv.TM_CCOEFF, cv.TM_CCOEFF_NORMED, cv.TM_CCORR, cv.TM_CCORR_NORMED, cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]    #   colorType:默认为0,表示使用RGB色彩类型, 1=使用灰度图, 2=表示二值化图像。    #   thresholdVal、thresholdMaxVal:当colorType=2时,才使用。    #   matchVal:tmplVal比较值。    #    # 返回值:    '''    def matchImage(self, srceenImgPath, ZoneCoordinate, galleryDir, setting = {'method':5, 'colorType':0, 'thresholdVal':0, 'thresholdMaxVal':255, 'matchVal':0.90 }):        # 判断文件是否存在;        tmplist = self.getGallery(galleryDir)        if len(tmplist) == 0:            # print u'图库目录空'            LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:图库目录空')            return None        srceenImgPath = unicode(srceenImgPath)        if os.path.exists(srceenImgPath) == True:            # 加载原图;            img_src = cv.imread(srceenImgPath.encode("gb18030"))            if img_src is None:                # print u'读取原图失败'                LoggingUtil.getDebugLogger().info(                    pyFileName,                     self.className,                     get_current_function_name(),                     'SDK:读取原图失败')                return None                        # 判断匹配区域是否整图,不是截图进行匹配;            bUseZoneImg = False            # sw,sh = img_src.shape[1],img_src.shape[0]#原图长宽;            if ZoneCoordinate is not None and (ZoneCoordinate[2] - ZoneCoordinate[0] != img_src.shape[1] or ZoneCoordinate[3] - ZoneCoordinate[1] != img_src.shape[0]):                bUseZoneImg = True                zoneImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"zoneImg_"+time.strftime("%Y%m%d%H%M%S", time.localtime())+".png")                image_util.saveCropPic(srceenImgPath,zoneImgPath,ZoneCoordinate)                img_src = cv.imread(zoneImgPath.encode("gb18030"))                if img_src is None:                    # print u'截图失败'                    LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:截图失败')                    return None            if setting["colorType"] == 1: # gray模式;                img_src = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY)            elif setting["colorType"] == 2: # threshold模式;                img_src = cv.cvtColor(img_src, cv.COLOR_BGR2GRAY)                # 将灰阶转成二值化图像;                img_src = cv.threshold(img_src, setting["thresholdVal"], setting["thresholdMaxVal"], cv.THRESH_BINARY)[1]            #加载要搜索的图像模板;            w,h = 0, 0            img_tmp = None            tmpVal, tmpLoc = 0,[0,0]            # listResult = []            result = {"tmpVal":0, "galleryFile":"", "coordinate":[0,0,0,0]}            # 遍历图库,找到最合适的            for file in tmplist:                # result = {"result": False, "tmpVal":0, "galleryFile":"", "coordinate":[0,0,0,0]}                # result = {"tmpVal":0, "galleryFile":"", "coordinate":[0,0,0,0]}                img_tmp = cv.imread(file.encode('gb18030'))                if img_tmp is None:                    # print u'模板图库相片加载失败'                    LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:模板图库相片加载失败')                    continue                if setting["colorType"] == 1: # gray模式;                    img_tmp = cv.cvtColor(img_tmp, cv.COLOR_BGR2GRAY)                elif setting["colorType"] == 2: # threshold模式;                    img_tmp = cv.cvtColor(img_tmp, cv.COLOR_BGR2GRAY)                    # 将灰阶转成二值化图像;                    img_tmp = cv.threshold(img_tmp, setting["thresholdVal"], setting["thresholdMaxVal"], cv.THRESH_BINARY)[1]                # 模板匹配;                w,h = img_tmp.shape[1], img_tmp.shape[0]                tmpVal, tmpLoc = self.templMatch(img_src, img_tmp, {'method':setting["method"], 'colorType':0 })                if bUseZoneImg == True:                    x,y = tmpLoc[0] + ZoneCoordinate[0],tmpLoc[1] + ZoneCoordinate[1]                else:                    x,y = tmpLoc[0], tmpLoc[1]                if setting["method"] == cv.TM_SQDIFF_NORMED or setting["method"] == cv.TM_SQDIFF:                    # if result["tmpVal"] > tmpVal:                    if tmpVal < (1-setting["matchVal"]):                        if result["tmpVal"] < 1-tmpVal:                            result["tmpVal"] = 1-tmpVal                            result["coordinate"] = [x,y,x+w,y+h]                            result["galleryFile"] = file                        # break                else:                    # if result["tmpVal"] < tmpVal:                    if tmpVal > setting["matchVal"]:                        if result["tmpVal"] < tmpVal:                            result["tmpVal"] = tmpVal                            result["coordinate"] = [x,y,x+w,y+h]                            result["galleryFile"] = file                        # break                                # if setting["method"] == cv.TM_SQDIFF_NORMED or setting["method"] == cv.TM_SQDIFF:                #     if result["tmpVal"] < (1 - setting["matchVal"]):                #         listResult.append(result)                # else:                #     if result["tmpVal"] > setting["matchVal"]:                #         listResult.append(result)                # print result["result"], result["tmpVal"],result["coordinate"],result["galleryFile"].decode('gb18030'),            #end for            if result["tmpVal"] == 0:                LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:模板匹配度为0')                return None            return result            # return listResult        else:            # print u'文件不存在'            LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:文件不存在')            return None        '''    # 描述:单一模板匹配;    # 参数:    # srceenImgPath:原图路径,即TV截图;    # ZoneCoordinate:要匹配的区域    # templImgPath:单模板文件路径    # setting:设定值    # 注意:templ对象,在screenImg中可能存在多个匹配度符合要求的区域。    '''    def matchSingleImage(self, srceenImgPath, ZoneCoordinate, templImgPath, setting = {'method':5, 'colorType':0, 'thresholdVal':0, 'thresholdMaxVal':255, 'matchVal':0.90 }):        srceenImgPath = unicode(srceenImgPath)        templImgPath = unicode(templImgPath)        if os.path.exists(srceenImgPath) == True and os.path.exists(templImgPath) == True:            # 加载原图;            srceenImg = cv.imread(srceenImgPath.encode("gb18030"))            if srceenImg is None:                # print u'读取原图失败'                LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:读取原图失败')                return None            # 判断匹配区域是否整图,不是截图进行匹配;            bUseZoneImg = False            # sw,sh = srceenImg.shape[1],srceenImg.shape[0]#原图长宽;            if ZoneCoordinate is not None and (ZoneCoordinate[2] - ZoneCoordinate[0] != srceenImg.shape[1] or ZoneCoordinate[3] - ZoneCoordinate[1] != srceenImg.shape[0]):                bUseZoneImg = True                zoneImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"zoneImg_"+time.strftime("%Y%m%d%H%M%S", time.localtime())+".png")                image_util.saveCropPic(srceenImgPath,zoneImgPath,ZoneCoordinate)                srceenImg = cv.imread(zoneImgPath.encode("gb18030"))                if srceenImg is None:                    # print u'截图失败'                    LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:截图失败')                    return None                        if ZoneCoordinate is None or ZoneCoordinate is []:                ZoneCoordinate = [0, 0, srceenImg.shape[1], srceenImg.shape[0]]            #加载图像模板;            w,h = 0, 0            img_tmp = None            tmpVal, tmpLoc = 0,[0,0]            result = {"tmpVal":0, "coordinate":[0,0,0,0]}            # 对比图库            img_tmp = cv.imread(templImgPath.encode('gb18030'))            if img_tmp is None:                # print u'模板图库相片加载失败'                LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:模板图库相片加载失败')                return None            # 模板匹配;            w,h = img_tmp.shape[1], img_tmp.shape[0]            tmpVal, tmpLoc = self.templMatch(srceenImg, img_tmp, setting)            result["tmpVal"] = tmpVal            if bUseZoneImg == True:                x,y = tmpLoc[0] + ZoneCoordinate[0],tmpLoc[1] + ZoneCoordinate[1]                result["coordinate"] = [x,y,x+w,y+h]            else:                result["coordinate"] = [tmpLoc[0],tmpLoc[1],tmpLoc[0]+w,tmpLoc[1]+h]            if setting["method"] == cv.TM_SQDIFF_NORMED or setting["method"] == cv.TM_SQDIFF:                if result["tmpVal"] < (1-setting["matchVal"]):                    return result            else:                if result["tmpVal"] > setting["matchVal"]:                    return result            # print result["result"], result["tmpVal"]            return None        else:            # print u'文件不存在'            LoggingUtil.getDebugLogger().info(                        pyFileName,                         self.className,                         get_current_function_name(),                         'SDK:文件不存在')            return None    '''        # 描述:获取矩形1在矩形2的方位;        # 参数:box1,box2矩形。        # 返回值:        # 左上:0 正上:1 右上:2        # 正左:3 正右:4        # 左下:5 正下:6 右下:7        # '''    def getOrientation(self, box1, box2):        # 矩形长宽;        w1,h1 = box1[2]-box1[0],box1[3]-box1[1]        # w2,h2 = box2[2]-box2[0],box2[3]-box2[1]        # 矩形中心点;        cx1,cy1 = box1[0]+w1/2,box1[1]+h1/2        # cx2,cy2 = box2[0]+w2/2,box2[1]+h2/2        # box1在box2右方;        if box1[0] >= box2[2]:            # 正右方;            if cy1 > box2[1] and cy1 < box2[3]:                return 4            # 右上方;            if cy1 < box2[1]:                return 2            # 右下方;            if cy1 > box2[3]:                return 7        # box1在box2下方;        if box1[1] >= box2[3]:            # 正下方;            if cx1 > box2[0] and cx1 < box2[2]:                return 6            # 左下方;            if cx1 < box2[0]:                return 5             # 右下方;            if cx1 > box2[2]:                return 7        # box1在box2左方;        if box1[2] <= box2[0]:            # 正左方;            if cy1 > box2[1] and cy1 < box2[3]:                return 3            # 左上方;            if cy1 < box2[1]:                return 0            # 左下方;            if cy1 > box2[3]:                return 5        # box1在box上方;        if box1[3] <= box2[1]:            # 正上方;            if cx1 > box2[0] and cx1 < box2[2]:                return 1            # 左上方;            if cx1 < box2[0]:                return 0            # 右上方;            if cx1 > box2[2]:                return 2                # box1在box2里面;        return -1        '''        # 描述:由两矩形的中心点来判别方位;        #         #         # '''    def getOrientationEx(self, box1, box2):        # 矩形长宽;        w1,h1 = box1[2]-box1[0],box1[3]-box1[1]        # w2,h2 = box2[2]-box2[0],box2[3]-box2[1]        # 矩形中心点;        cx1,cy1 = box1[0]+w1/2,box1[1]+h1/2        # cx2,cy2 = box2[0]+w2/2,box2[1]+h2/2        # box1在box2右方;        if cx1 > box2[2]:            # 正右方;            if cy1 > box2[1] and cy1 < box2[3]:                return 4            # 右上方;            if cy1 < box2[1]:                return 2            # 右下方;            if cy1 > box2[3]:                return 7        # box1在box2下方;        if cy1 > box2[3]:            # 正下方;            if cx1 > box2[0] and cx1 < box2[2]:                return 6            # 左下方;            if cx1 < box2[0]:                return 5             # 右下方;            if cx1 > box2[2]:                return 7        # box1在box2左方;        if cx1 < box2[0]:            # 正左方;            if cy1 > box2[1] and cy1 < box2[3]:                return 3            # 左上方;            if cy1 < box2[1]:                return 0            # 左下方;            if cy1 > box2[3]:                return 5        # box1在box上方;        if cy1 < box2[1]:            # 正上方;            if cx1 > box2[0] and cx1 < box2[2]:                return 1            # 左上方;            if cx1 < box2[0]:                return 0            # 右上方;            if cx1 > box2[2]:                return 2                # box1在box2里面;        return -1    '''        # 描述:生成网络数据。        # 参数:一组矩形坐标。        # 返回值:分组的矩形坐标;        # 注意:        #   给定的一组矩形,如果不是继续的一组网格矩形,无法判断缺少的矩形位置.        #         # '''    def generateGrid(self,listRects):        ret = 0        # 1、先上下排序,分层级;                for i in range(len(listRects)-1):            for j in range(0, len(listRects)-i-1):                ret = self.getOrientation(listRects[j], listRects[j+1])                if ret in [5,6,7]:                    listRects[j], listRects[j+1] = listRects[j+1], listRects[j]                # 2、层级分组;        listLyaer = []        lastIndex = 0        for i in range(0,len(listRects)-1):            ret = self.getOrientation(listRects[i],listRects[i+1])            if ret in (0,1,2):                # 将同一行的所有网格添加为一个数组元素;                listLyaer.append(listRects[lastIndex:i+1])                lastIndex = i+1        # 如果有最后一个,自成一组。        # if i < len(listRects)-1:        if lastIndex < len(listRects):            listLyaer.append(listRects[lastIndex::])        # 3、分组后,再每一组排序;        for row in listLyaer:            for i in range(len(row)-1):                for j in range(0, len(row)-i-1):                    ret = self.getOrientation(row[j], row[j+1])                    if ret == 4:                        row[j], row[j+1] = row[j+1], row[j]                # 4、返回结果。        return listLyaer    '''        # 描述:查找指定矩形在网格中的坐标;        # 参数:        # rect:要查找的盒子坐标;        # listGrid:网格        #         # 返回:行、列、是否边界(0:未到边界,1:右边界,-1:左边界;2:最后一格; -2:最前一格; 3:最后一格且该行只有一格)        #        # '''    def getGridCoordinate(self, rect, listGrid):        result,boundary = False,0        try:            grid,cell = None,None            for row in range(0,len(listGrid)):                grid = listGrid[row]                for col in range(0,len(grid)):                    cell = grid[col]                    # 包含在内;                    if rect[0] <= cell[0] and rect[1] <= cell[1] and rect[2] >= cell[2] and rect[3] >= cell[3]:                        result = True                        if col == len(grid)-1:                            boundary = 1 #已到右边界;                        elif col == 0:                            boundary = -1 #左边界;                        break                if result == True:                    break        except Exception, e:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:循环异常'+str(e))                if result == True:            # 再判断,是否是最后一格;            if row == len(listGrid) - 1 and col == len(listGrid[len(listGrid) - 1]) - 1:                boundary = 2 # 最后一格;                if col == 0:#单格一行;                    boundary = 3                print u'最后一格:'.encode('gbk'),row,col,boundary            # 判断是不是最前一格;            if row == 0 and col == 0:                boundary = -2                print u'最前一格:'.encode('gbk'),row,col,boundary            return row,col,boundary        else:            return -1,-1,boundary    '''        # 描述:顺(正)序查找目标焦点框        # 参数:        #         #         # '''    def sequentialSearch(self, curRow, curBoundary, remoteCtrlTimes, listRect, listGrid, dict, findFunc):        row,boundary,keyDirection = 0,0,True        curText,curTextArea,curFocusArea = None,None,None        ctrl_times = int((1 + 0.5)*remoteCtrlTimes + 2)         if curBoundary == 1:#右边界。            # 向下遥控;            self.redRat3.sendKey('down')            keyDirection = False # 向左遥控;            # 截图;            dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_"+time.strftime("%Y%m%d%H%M%S", time.localtime())+".png")            self.vp.takePicture(dict["TVShotPath"])            ocr_result, curFocusArea = findFunc(dict)            if ocr_result == True:                return True, curFocusArea                result = False        for i in range(ctrl_times):            if keyDirection == True:                #向右遥控;                self.redRat3.sendKey('right')            else:                #向左遥控;                self.redRat3.sendKey('left')            # 按键后,获取当前焦点;            dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")            self.vp.takePicture(dict["TVShotPath"])            ocr_result, curFocusArea = findFunc(dict)            if ocr_result == True:                result = True                break            # 不是目标焦点,继续遥控;            row,col,boundary = self.getGridCoordinate(curFocusArea,listGrid)            print u'curRow,curCol,curBoundary',row,col,boundary            if boundary == 1 or boundary == -1:                # 向下遥控;                self.redRat3.sendKey('down')                keyDirection = True if boundary == -1 else False # 向左或向右遥控;                dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")                self.vp.takePicture(dict["TVShotPath"])                ocr_result, curFocusArea = findFunc(dict)                if ocr_result == True:                    result = True                    break                return result, curFocusArea    '''        # 描述:反序查找目标焦点框;        # 参数:        #         #         # '''    def reverseSearch(self, curRow, curBoundary, remoteCtrlTimes, listRect, listGrid, dict, findFunc):        row,boundary,keyDirection = 0,0,False        curText,curTextArea,curFocusArea = None,None,None        ctrl_times = int((1 + 0.5)*remoteCtrlTimes + 2)         if curBoundary == -1:#左边界;            # 向下遥控;            self.redRat3.sendKey('up')            keyDirection = True # 向右遥控;            # 截图;            dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_"+time.strftime("%Y%m%d%H%M%S", time.localtime())+".png")            self.vp.takePicture(dict["TVShotPath"])            ocr_result, curFocusArea = findFunc(dict)            if ocr_result == True:                return True, curFocusArea                result = False        for i in range(ctrl_times):            if keyDirection == True:                #向右遥控;                self.redRat3.sendKey('right')            else:                #向左遥控;                self.redRat3.sendKey('left')            # 按键后,获取当前焦点;            dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")            self.vp.takePicture(dict["TVShotPath"])            ocr_result, curFocusArea = findFunc(dict)            if ocr_result == True:                result = True                break            # 不是目标焦点,继续遥控;            row,col,boundary = self.getGridCoordinate(curFocusArea,listGrid)            print u'curRow,curCol,curBoundary',row,col,boundary            if boundary == 1 or boundary == -1:                # 向上遥控;                self.redRat3.sendKey('up')                keyDirection = False if boundary == 1 else True # 向左或向右遥控;                dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")                self.vp.takePicture(dict["TVShotPath"])                ocr_result, curFocusArea = findFunc(dict)                if ocr_result == True:                    result = True                    break                return result, curFocusArea    def SearchEx(self, listGrid, dict, findFunc, searchType = True):        result = False        # 按键方向:True->右;False->左;        keyDirection = False        # 上一行行号;        lastRow = -1         # 遍历尾行的行号;        endRow = 0         #下一行按键;        nextRow = 'up'        # 以上是逆序时的预设值;        if searchType == True: # 正序查找;            endRow = len(listGrid)-1            keyDirection = True            nextRow = 'down'        while True:            # 获取当前坐标(x,y)及边界性;            dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")            self.vp.takePicture(dict["TVShotPath"])            ocr_result, curFocusArea = findFunc(dict)            if curFocusArea is None:                break            if ocr_result == True:                result = True                break            row, col, boundary = self.getGridCoordinate(curFocusArea, listGrid)            # 判断是否遍历完最后一行;            if lastRow == endRow:                # 根据按键方向判断是否到达尾行尾格;                if keyDirection and col == len(listGrid[row])-1:                    break                if not keyDirection and col == 0:                    break            # 记录当前行;            lastRow = row            if boundary == 0:                # 没找到,遥控下一格;                if keyDirection == True:                    self.redRat3.sendKey('right')                else:                    self.redRat3.sendKey('left')            elif boundary == 1:#最右                if keyDirection == True:                    keyDirection = not keyDirection                    self.redRat3.sendKey(nextRow)                else:                    self.redRat3.sendKey('left')            elif boundary == 2:#最后一行最后一格;(该行有多格)                if searchType == True:                    break#结束遍历;                else:                    if keyDirection == False:                        self.redRat3.sendKey('left')            elif boundary == 3:#最后一行最后一格;(该行只有一格)                if searchType == True:                    break#结束遍历;                else:                    keyDirection = not keyDirection                    self.redRat3.sendKey(nextRow)            elif boundary == -1:#最左;                if keyDirection == False:                    keyDirection = not keyDirection                    self.redRat3.sendKey(nextRow)                else:                    self.redRat3.sendKey('right')            elif boundary == -2:#最前一格;                if searchType == False:                    break#结束遍历;                else:                    if keyDirection == True:                        self.redRat3.sendKey('right')        return result    '''        # 描述:到达网格的第一个盒子焦点;        #         #         #         # '''    def reach1stBox(self, listGrid, cropArea, grayVal, maxGrayVal, bInside, minPeri, maxPeri, minArea, maxArea, find_1st = True):         result = True                      while True:            # 当前焦点位置;            curFocusBox = self.findCurrentFocusBoxInType04(cropArea,grayVal,maxGrayVal,bInside,minPeri,maxPeri,minArea,maxArea)[0]            if curFocusBox is None:                result = False                break            # 获取行列坐标标;            row, col, boundary = self.getGridCoordinate(curFocusBox, listGrid)            if row == 0 and col == 0:# and boundary == -1:                result = True                break            if row > 0:                self.redRat3.sendKey('up')            elif row == 0 and boundary != -2:                self.redRat3.sendKey('left', col, 0.5)        return result    '''        # 描述:查找当前焦点框信息;        #         #         #         # '''    def findCurrentFocusFrameInType6(self, dict):        # 1、获取当前轮廓;        try:            bInside = dict["InsideContours"]# 是否使用内轮廓;        except:            bInside = False        contourRect = self.getGrayBinaryContour(            dict["TVShotPath"],            dict["ZoneCoordinate"],            dict["ZoneThreshold"],            dict["ZoneMaxThreshold"],            bInside,            dict["RenderingsMinGirth"],            dict["RenderingsMaxGirth"],            dict["RenderingsMinArea"],            dict["RenderingsMaxArea"])        if contourRect == None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:没有找到轮廓区域')            return False,None        #endif        # 计算文本位置;        realTextBox = self.findCurrentFocusTextBox(contourRect, dict["RenderingsArea"], dict["RenderingsTextArea"][0:4])        if realTextBox is None:            return False,contourRect        ocrImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"OCR_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        image_util.saveCropPic(dict['TVShotPath'], ocrImgPath, realTextBox)        result, realTextBox = self.OCR.findPicStr(dict['TargetText'], ocrImgPath, dict['RenderingsTextArea'][4],dict['RenderingsTextArea'][5],dict['RenderingsTextArea'][6],dict['RenderingsTextArea'][7])        return result, contourRect    '''        # 描述:查找目标焦点框之type6.        # 参数:        #         # 返回值:成功找到焦点返回True,否则返回False;        #         # '''    def findTargetFocusFrameInType6(self,dict):            # 1、计算出几行几列;        listRect = []        for focus in dict["FocusList"]:            listRect.append(focus["focus_area"])        # 生成网格;        listGrid = self.generateGrid(listRect)        # 正反序查找;        result = self.SearchEx(listGrid, dict, self.findCurrentFocusFrameInType6, True)        if result == False:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:逆序查找')            result = self.SearchEx(listGrid, dict, self.findCurrentFocusFrameInType6, False)        return result    #end    '''        # 描述:图像形态学处理。        #         #         # '''    def preProcess(self, grayImage,setting):        # 1、sobel算子,x方向求梯度;        sobel = cv.Sobel(grayImage, cv.CV_8U, 1, 0, ksize = 3)        # 2、二值化;        if 'gray' in setting:            binary = cv.threshold(sobel, setting['gray'], 255, cv.THRESH_BINARY+cv.THRESH_OTSU)[1]        else:            binary = cv.threshold(sobel, 0, 255, cv.THRESH_BINARY+cv.THRESH_OTSU)[1]        binary_path = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"binary_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        cv.imwrite(binary_path, binary)          # 第一次;        first,second,third = None,None,None        ksize = (1,1)        ksize = tuple(setting["first"][1:3])        kernel = cv.getStructuringElement(setting["first"][3], ksize)        if setting["first"][0] == "dilate":            first = cv.dilate(binary, kernel, setting["first"][4])        else:            first = cv.erode(binary, kernel, setting["first"][4])        # 第二次;        second = None        if 'second' in setting and len(setting["second"]) != 0:            ksize = tuple(setting["second"][1:3])            kernel = cv.getStructuringElement(setting["second"][3], ksize)            if setting["second"][0] == "dilate":                second = cv.dilate(first, kernel, setting["second"][4])            else:                second = cv.erode(first, kernel, setting["second"][4])        else:            second = first        # 第三次;        third = None        if "third" in setting and len(setting["third"]) != 0:            ksize = tuple(setting["third"][1:3])            kernel = cv.getStructuringElement(setting["third"][3], ksize)            if setting["third"][0] == "dilate":                third = cv.dilate(second, kernel, setting["third"][4])            else:                third = cv.erode(second, kernel, setting["third"][4])        else:            third = second        # 7. 存储中间图片        tmpdir = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"binary_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        cv.imwrite(tmpdir, binary)        tmpdir = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"first_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        cv.imwrite(tmpdir, first)        if second is not None:            tmpdir = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"second_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")            cv.imwrite(tmpdir, second)        if third is not None:            tmpdir = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"third_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")            cv.imwrite(tmpdir, third)        return third if third is not None else second        '''        # 描述:查找文字区域        #         #         #         # '''    def findTextRegion(self, img, minGirth, maxGirth, minArea, maxArea):        # 1. 查找轮廓        contours = cv.findContours(img, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)[1]        if len(contours) == 0:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:没有找文本到轮廓')            return None            # 2. 过滤        listCnt = []        maxBox, maxCnt = 0, None        for i in range(len(contours)):            cnt = contours[i]            # 计算该轮廓的面积            area = cv.contourArea(cnt)             perimeter = cv.arcLength(cnt, True)            # 符合结果的,保存在list中;            if area > minArea and area < maxArea and perimeter > minGirth and perimeter < maxGirth:                listCnt.append(cnt)                if len(listCnt) == 0:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:没有找到符合目标的轮廓')            return None            # 只保留面积最大的;        for i in range(len(listCnt)):            cnt = listCnt[i]            # 计算该轮廓的面积            area = cv.contourArea(cnt)             if(maxBox < area):                maxBox = area                maxCnt = cnt        # 找到最小的矩形,该矩形可能有方向        rect = cv.minAreaRect(maxCnt)        print ("rect is: ",rect)        # box是四个点的坐标        box = cv.boxPoints(rect)        box = np.int0(box)        # print 'box',box        if rect[2] > -45.0:            rect = [box[1][0],box[1][1],box[3][0],box[3][1],]        else:#-90            rect = [box[2][0],box[2][1],box[0][0],box[0][1],]        return rect    '''        # 描述:查找当前焦点的文本轮廓。        # 参数:        #         #         # 返回值:返回文本内容。        #         # '''    def findTextcontourRect(self, tvShotPath, dict):        coordinate = dict["ZoneCoordinate"]        thresholdVal = dict["ZoneThreshold"]        maxThresholdVal = dict["ZoneMaxThreshold"]        try:            maxGirth = dict["RenderingsMaxGirth"]# 效果图周长上限;(最大值)            minGirth = dict["RenderingsMinGirth"]# 效果图周长下限;(最小值)            maxArea = dict["RenderingsMaxArea"]# 效果图面积上限;(最大值)            minArea = dict["RenderingsMinArea"]# 效果图面积下限;(最小值)        except:            maxGirth = 1000000# 效果图周长上限;(最大值)            minGirth = 10# 效果图周长下限;(最小值)            maxArea = 1000000# 效果图面积上限;(最大值)            minArea = 100# 效果图面积下限;(最小值)        ocrtype = dict["ocrtype"]        language = dict["language"]        setting = dict["setting"]        # 按区域截图,在区域中查找轮廓。        zoneImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"zoneImg_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        image_util.saveCropPic(tvShotPath, zoneImgPath, coordinate)        imgTV = cv.imread(zoneImgPath.encode("gb18030"))        # 判断对象有效性;        if imgTV is None:            # print u'效果图对象空,可能文件路径无效'            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:效果图对象空,可能文件路径无效')            return None,None                # 将截图转成灰阶;        imgGray = cv.cvtColor(imgTV, cv.COLOR_BGR2GRAY)        # 高斯模糊;        imgGray = cv.GaussianBlur(imgGray, (3, 3), 0)        # 将灰阶转成二值化图像;        thresh = cv.threshold(imgGray, thresholdVal, maxThresholdVal, cv.THRESH_BINARY)[1]        tmpdir = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"thresh_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        cv.imwrite(tmpdir, thresh)        # 图像形态学处理;        dilation = self.preProcess(thresh,setting)        # 查找和筛选文字区域        text_area = self.findTextRegion(dilation,minGirth,maxGirth,minArea,maxArea)        if text_area is None:            return None,None        ocrImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"OCR_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        image_util.saveCropPic(dict['TVShotPath'], ocrImgPath, text_area)        ocr_result, ocr_text = self.OCR.findPicStr(dict['TargetText'], ocrImgPath, language, ocrtype, dict['ocrImgInfo'],dict['ignoreChar'])                return ocr_result, ocr_text    '''        # 描述:查找当前焦点框之type7.        # 参数:        #         # 返回:        #        # 注意:只适用于左右遥控按键.        #          # '''    def findCurrentFocusFrameInType7(self,dict):        if 'setting' not in dict:            dict["setting"] = {                "first":["erode",2,2,0,1],      # 第一次操作是腐蚀还是膨胀,内核大小,内核形状,操作次数                "second":["dilate",30,9,0,1],   # 内核大小,内核形状,操作次数                "third":["dilate",24,10,0,2]    # 内核大小,内核形状,操作次数            }                # 先正序查找;        result = False        target_text,last_text = '',''        sendTimes = dict["SendTimes"]        changeTimes = -1        while sendTimes > 0:            # 电视截图;            TVShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")            self.vp.takePicture(TVShotPath)            # 查找文本轮廓            ocr_result, target_text = self.findTextcontourRect(TVShotPath, dict)            if ocr_result == True:                result = True                break            # 发送右按钮;            self.redRat3.sendKey('right')            sendTimes -= 1            if last_text != target_text:                last_text = target_text                changeTimes += 1        # 正序未找到,逆序查找;        if result == False:            #向左发送changeTimes+1次,回到原点;            keys = ['left']*(changeTimes+1)            self.redRat3.sendKeys(keys)            sendTimes = dict["SendTimes"]            while sendTimes > 0:                # 电视截图;                TVShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")                self.vp.takePicture(TVShotPath)                ocr_result, target_text = self.findTextcontourRect(TVShotPath, dict)                if ocr_result == True:                    result = True                    break                # 发送左按钮;                self.redRat3.sendKey('left')                sendTimes -= 1                return result    def getHSVBinaryContour(self, tvShotPath, cropArea, hsvVal, maxHsvVal, bInside, minPeri, maxPeri, minArea, maxArea, find_1st = True):        contourRect = [0,0,0,0]#结果:x1,y1,x2,y2;        # 判断文件是否存在;        if os.path.exists(tvShotPath) == False:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片路径不存在'+tvShotPath)            return None                # 打开图片;        img_tvShot = cv.imread(tvShotPath)        if img_tvShot is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片对象空')            return None                # 只保留区域部分;        try:            img_crop = np.array(img_tvShot[cropArea[1]:cropArea[3], cropArea[0]:cropArea[2]])        except:            img_crop = img_tvShot        cv.imwrite(LoggingUtil.getCaseRunLogDirPath() + "crop_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png", img_crop)        # 判断对象有效性;        if img_crop is None:            # print u'效果图对象空,可能文件路径无效'            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:区域截图对象空,可能文件路径无效')            return None                        # 将截图转成灰阶;        img_hsv = cv.cvtColor(img_crop, cv.COLOR_BGR2HSV)        # 根据参数的阀值得到特定颜色区域;        img_binary = cv.inRange(img_hsv, tuple(hsvVal),tuple(maxHsvVal))         # 图像形态学内核对象;        kernerl = cv.getStructuringElement(cv.MORPH_RECT, ksize=(3,3))        # 开操作,去噪点;        img_binary = cv.morphologyEx(img_binary,cv.MORPH_OPEN,kernerl)        # 闭操作,连通域;        img_binary = cv.morphologyEx(img_binary,cv.MORPH_CLOSE,kernerl)        # 获取二值化图像的轮廓;        area, perimeter = 0.0, 0.0        if bInside == False:#外轮廓            contours, hierarchy = cv.findContours(img_binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[1:3]        else:#内轮廓            contours, hierarchy = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)[1:3]                listBox = []        # 过滤掉不符合要求的轮廓;        x, y, w, h,result = 0,0,0,0,False        for cnt in contours:            # 面积;            area = cv.contourArea(cnt)            # 周长;            perimeter = cv.arcLength(cnt, True)            # 获取满足条件的值;            if area >= minArea and area <= maxArea and perimeter >= minPeri and perimeter <= maxPeri:                # 直边矩形,(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高;                x, y, w, h = cv.boundingRect(cnt)                # print u'boundingRect=',x,y,w,h                LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:当前找到的轮廓='+str((x,y,w,h)))                # 判断矩形是否包含在区域内;                # 在区域内截图判断;                x = x + cropArea[0]                y = y + cropArea[1]                contourRect = [x,y,x+w,y+h]                # 如果只找第一个;                if find_1st == True:                    result = True                    break                # 多个;                listBox.append(contourRect)            #endif        #endfor        # 只返回满足条件的第一个值;        if find_1st == True:            return contourRect if result == True else None        else:            return listBox    #end    def findCurrentFocusFrameInType8(self,dict):        # 1、获取当前轮廓;        try:            bInside = dict["InsideContours"]# 是否使用内轮廓;        except:            bInside = False        contourRect = self.getHSVBinaryContour(            dict["TVShotPath"],            dict["ZoneCoordinate"],            dict["ZoneThreshold"],            dict["ZoneMaxThreshold"],            bInside,            dict["RenderingsMinGirth"],            dict["RenderingsMaxGirth"],            dict["RenderingsMinArea"],            dict["RenderingsMaxArea"])        if contourRect == None:            # print u'没有找到轮廓区域'            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:没有找到轮廓区域')            return False,None        #endif        # 计算文本位置;        realTextBox = self.findCurrentFocusTextBox(contourRect, dict["RenderingsArea"], dict["RenderingsTextArea"][0:4])        if realTextBox is None:            return False,contourRect        # # 获取文本内容;        ocrImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"OCR_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        image_util.saveCropPic(dict['TVShotPath'], ocrImgPath, realTextBox)        result, realTextBox = self.OCR.findPicStr(dict['TargetText'], ocrImgPath, dict['RenderingsTextArea'][4],dict['RenderingsTextArea'][5],dict['RenderingsTextArea'][6],dict['RenderingsTextArea'][7])        return result, contourRect    def findTargetFocusFrameInType8(self,dict):        # 1、查找当前焦点框;        dict["TVShotPath"] = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(dict["TVShotPath"])        ocr_result, curFocusArea = self.findCurrentFocusFrameInType8(dict)        if curFocusArea is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), u'SDK-Type8:当前焦点框空')            return False        result = False        # 2、当前焦点是否目标焦点;        if ocr_result == True:            # curText, curTextArea, curFocusArea            return True        else:            # 3、计算出几行几列;            listRect = []            for focus in dict["FocusList"]:                listRect.append(focus["focus_area"])                        listGrid = self.generateGrid(listRect)            # 4、当前焦点在哪个位置;            curRow,curCol,curBoundary = self.getGridCoordinate(curFocusArea,listGrid)            # 5、分正序查找和逆序查找两次查找。            keyDirection = True # True表示向右发送遥控,False表示向左发送遥控;            # 将多维数组转一维;            listRect = list(chain(*listGrid))            # 行数,列数;            rows,cols = len(listGrid),len(listGrid[0])            # 剩余遥控次数;            ctrl_times = len(listRect) - (curRow+1)*cols + curCol            # 5.1、顺序查找;            result, curFocusArea = self.sequentialSearch(curRow, curBoundary, ctrl_times, listRect, listGrid, dict, self.findCurrentFocusFrameInType8)            # 5.2、逆序查找;            if result == False:                curRow,curCol,curBoundary = self.getGridCoordinate(curFocusArea,listGrid)                ctrl_times = curRow*cols + curCol                result, curFocusArea = self.reverseSearch(curRow, curBoundary, ctrl_times, listRect, listGrid, dict, self.findCurrentFocusFrameInType8)            return result    #end    '''    # 描述:计算出两矩形的正包含的相交百分比。(以相交面积/最小矩形面积)    #     # 返回值:正包含的相交百分比    # '''    # 两矩形是否相交,返回相交百分比;    def bbOverlap(self, box1, box2):        # 外正四方;        if box1[0] > box2[2]:            return 0.0        if box1[1] > box2[3]:            return 0.0        if box1[2] < box2[0]:            return 0.0        if box1[3] < box2[1]:            return 0.0               # 计算相交长宽;        colInt = abs(min(box1[2], box2[2]) - max(box1[0], box2[0]))        rowInt = abs(min(box1[3], box2[3]) - max(box1[1], box2[1]))        # 计算相交面积        overlapArea = colInt * rowInt        # 各自面积        area1 = (box1[2]-box1[0])*(box1[3]-box1[1])        area2 = (box2[2]-box2[0])*(box2[3]-box2[1])        # 是否全包含;        # if overlapArea == area1 or overlapArea == area2:            # return 1.0        # 返回相交比;        # return float(overlapArea) / (area1 + area2 - overlapArea)        return float(overlapArea) / min(area1, area2)#以最小面积的占用比,作为相交比,可计算出全包含。    '''        # 描述:返回目标焦点在当前选中焦点的哪个方向。        # 参数:        # focusType:查找当前焦点的方式。        # focusDict:查找当前焦点的参数。        # matchDicts:查找目标焦点的模板匹配参数。        # 返回值:        #         # '''    def findTargetFocusDirection(self, focusType, focusDict, matchDict):        # 查找当前焦点;        curFocusText, curFocusTextArea, curFocusArea = None,None,None        if focusType == 0:            curFocusText, curFocusTextArea, curFocusArea = self.getBorderRectangleFocusArea(focusDict["RenderingsPath"],focusDict["TVShotPath"],focusDict["FocusList"],focusDict["FocusDirection"],focusDict["RenderingsBorderWide"],)        elif focusType == 1:            curFocusText, curFocusTextArea, curFocusArea = self.getColoringleFocusArea(focusDict["RenderingsPath"],focusDict["TVShotPath"],focusDict["FocusList"],focusDict["FocusDirection"],)        elif focusType == 2:            curFocusText, curFocusTextArea, curFocusArea = self.getZoomFocusArea(focusDict["RenderingsPath"],focusDict["TVShotPath"],focusDict["FocusList"],focusDict["FocusDirection"],)        elif focusType == 3:            curFocusText, curFocusTextArea, curFocusArea = self.autoRecognitionFocusArea(focusDict,)        elif focusType == 4:            curFocusText, curFocusTextArea, curFocusArea = self.getSelectFocusArea(focusDict,)        elif focusType == 5:            if focusDict["setting"] == None:                curFocusArea = self.matchSingleImage(focusDict["TVShotPath"],focusDict["ZoneCoordinate"],focusDict["TemplatePath"])            else:                curFocusArea = self.matchSingleImage(focusDict["TVShotPath"],focusDict["ZoneCoordinate"],focusDict["TemplatePath"],focusDict["setting"])                # 获取模板匹配结果,找到目标焦点区域坐标;        if matchDict["setting"] == None:            tagFocusArea = self.matchSingleImage(matchDict["TVShotPath"],matchDict["ZoneCoordinate"],matchDict["TemplatePath"])        else:            tagFocusArea = self.matchSingleImage(matchDict["TVShotPath"],matchDict["ZoneCoordinate"],matchDict["TemplatePath"],matchDict["setting"])                # 计算两矩形是否相交,返回正包含相交比.        overlap = self.bbOverlap(curFocusArea, tagFocusArea["coordinate"])        # 返回结果;        return curFocusText, curFocusTextArea, curFocusArea, tagFocusArea["coordinate"], overlap    '''        # 描述:焦点识别类型00:选中的焦点框边框外镶了一层有色边框,通过抓取这层边框颜色来识别焦点框。        #         #         # '''    def findCurrentFocusBoxInType00(self, dict):        # 当前电视机截图;        tvShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(tvShotPath)        # 选中焦点框的效果图;        effectPath = dict["EffectPath"]        # 焦点所在区域;        zoneBox = dict["ZoneCoordinate"]        # 效果图外边框厚度;        borderWidth = dict["BorderWidth"]        # 获取选中焦点框效果图的外边框的luv平均值.        effectImg = cv.imread(effectPath)        effectLuv = cv.cvtColor(effectImg, cv.COLOR_BGR2Luv)                # 将外边框拆分成4个矩形。        height,width = effectLuv.shape[0:2]        leftBox = [0, 0, borderWidth, height]        rightBox = [width - borderWidth, 0, width, height]        topBox = [borderWidth, 0, width - borderWidth, borderWidth]        bottomBox = [borderWidth, height - borderWidth, width - borderWidth, height]        # luv平均值;        avgluv = self.CIELuv.getMAverageLUV(effectLuv, [leftBox, rightBox, topBox, bottomBox])    '''        # 描述:焦点识别类型03:选中的焦点框背景色变成其他颜色,通过计算背景色获取上下两边直线来确定识别焦点框。        #         #         # '''    def findCurrentFocusBoxInType03(self, zoneBox, effectBox, effectColorBox, effectPath, matchVal):        # 当前电视机截图;        tvShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(tvShotPath)        # 判断文件是否存在;        if os.path.exists(tvShotPath) == False:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片路径不存在'+tvShotPath)            return None                if os.path.exists(effectPath) == False:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片路径不存在'+effectPath)            return None                # 判断区域是否在有效范围内;        # 略过……        # 打开图片;        img_tvShot = cv.imread(tvShotPath)        img_effect = cv.imread(effectPath)        if img_tvShot is None or img_effect is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片对象空')            return None        # effectColorBox中心点,用于取色;        cx,cy = effectColorBox[0] + int(effectColorBox[2] - effectColorBox[0])/2, effectColorBox[1] + int(effectColorBox[3] - effectColorBox[1])/2        focusBGColor = img_effect[cx,cy]        # 效果图宽、高        effectWidth, effectHeight = effectBox[2]-effectBox[0],effectBox[3]-effectBox[1]        # 水平、垂直        hLine1, hLine2 = [],[]        # 是否找到        bhLine1, bhLine2 = False,False        # 查找第一行与effectColor相近的颜色线条;        for y in range(zoneBox[1], zoneBox[3]):            for x in range(zoneBox[0], zoneBox[2]):                if bhLine1 == False:                    if self.CIELuv.isColorSimilar(img_tvShot[y][x],focusBGColor) == True:                        hLine1.append([x,y])                #end if            #end for                    # 判断本线是否符合要求;            if bhLine1 == False:                count = len(hLine1)                if float(count)/effectWidth > matchVal:                    bhLine1 = True                else:                    hLine1 = []        #end for        if len(hLine1) == 0:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:未找到第一行,长度为0')            return None                # 查找最后一行与effectColor相近的颜色线条;        zoneBox = [hLine1[0][0]-10, hLine1[0][1], hLine1[0][0] + effectWidth, hLine1[0][1] + effectHeight]        for y in range(zoneBox[3], zoneBox[1],-1):            for x in range(zoneBox[0], zoneBox[2]):                if bhLine2 == False:                    if self.CIELuv.isColorSimilar(img_tvShot[y][x],focusBGColor) == True:                        hLine2.append([x,y])                #end if            #end for             # 判断本线是否符合要求;            if bhLine2 == False:                count = len(hLine2)                if float(count)/effectWidth > matchVal:                    bhLine2 = True                else:                    hLine2 = []        #end for        if len(hLine2) == 0:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:未找到最后一行,长度为0')            return None                # 焦点区域;        focusBox = [hLine1[0][0], hLine1[0][1], hLine2[-1][0], hLine2[-1][1]]        # 返回结果;        # return True,focusBox        return focusBox    '''        # 描述:焦点识别类型04:选中的焦点框背景色变成其他颜色,通过二值化获取轮廓面积、周长来识别焦点框。        #         #         # '''    def findCurrentFocusBoxInType04(self, zoneBox, threshold, maxThreshold, bInside, minPeri, maxPeri, minArea, maxArea, find_1st = True):        contourRect = [0,0,0,0]#结果:x1,y1,x2,y2;        tvShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(tvShotPath)        # 获取轮廓;        contourRect = self.getGrayBinaryContour(tvShotPath, zoneBox, threshold, maxThreshold, bInside, minPeri, maxPeri, minArea, maxArea, find_1st)        # 返回结果;        if find_1st == True:            return contourRect,tvShotPath        else:            return contourRect,tvShotPath        '''        # 描述:焦点识别类型05:选中的焦点框明显与未选中时有差别,通过【多组图像的模板匹配】方式来识别焦点框。        #         #         # '''    def findCurrentFocusBoxInType05(self, zoneBox, focusDir):        tvShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(tvShotPath)        val = self.matchImage(tvShotPath, zoneBox, focusDir)        if val is None:            return None                return val["coordinate"]#,val["galleryFile"]    '''        # 描述:焦点识别类型06:选中的焦点框前景高亮着色,但背景是可变的,通过二值化获取大概轮廓,再膨胀腐蚀操作后得到最大轮廓来识别焦点框。        #         #         # '''    def findCurrentFocusBoxInType06(self, zoneBox, threshold, maxThreshold, minPeri = 10, maxPeri = 1000000, minArea = 100, maxArea = 1000000, setting = {"first":["erode",2,2,0,1], "second":["dilate",30,9,0,1],"third":["dilate",24,10,0,2]}):        tvShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(tvShotPath)                # 按区域截图,在区域中查找轮廓。        img_tvShot = cv.imread(tvShotPath)        if img_tvShot is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片路径可能无效'+tvShotPath)            return None        img_zone = image_util.cutImage(img_tvShot, zoneBox)        if img_zone is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:裁剪图片失败')            return None                # 将截图转成灰阶;        imgGray = cv.cvtColor(img_zone, cv.COLOR_BGR2GRAY)        # 高斯模糊;        imgGray = cv.GaussianBlur(imgGray, (3, 3), 0)        # 将灰阶转成二值化图像;        thresh = cv.threshold(imgGray, threshold, maxThreshold, cv.THRESH_BINARY)[1]        tmpdir = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"thresh_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        cv.imwrite(tmpdir, thresh)        # 图像形态学处理;        dilation = self.preProcess(thresh,setting)        # 查找和筛选文字区域        text_area = self.findTextRegion(dilation,minPeri,maxPeri,minArea,maxArea)        if text_area is None:            return None                return text_area    '''        # 描述:焦点识别类型07:选中的焦点框前景色变成其他颜色,但是背景可变,通过计颜色阀值来计算出轮廓,再通过周长面积过滤后来调识别焦点框。        #         #         # '''    def findCurrentFocusBoxInType07(self, zoneBox, threshold, maxThreshold, bInside, minPeri, maxPeri, minArea, maxArea):        tvShotPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"TVShot_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        self.vp.takePicture(tvShotPath)        return self.getHSVBinaryContour(tvShotPath,zoneBox,threshold,maxThreshold,bInside,minPeri,maxPeri,minArea,maxArea)    # 在多区域中找当前焦点;    def findCurrentFocusBox(self, listdict):        if len(listdict) == 0:            return None,None                # 遍历区域,查找当前焦点所在区域;        zType = -1        zData = []        zName = ''        bInside = False        # 当前焦点框坐标;        focus_box = None        for zone in listdict:            zName = zone["zoneName"]            zType = zone["zoneType"]            zData = zone["zoneData"]            # print '打印->'.encode('gbk'),zName.encode('gbk'),zType            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:当前遍历Zone:'+zName+',类型:'+str(zType))                        try:                bInside = zData["InsideContours"]# 是否使用内轮廓;            except:                bInside = False                        if zType == 3:                focus_box = self.findCurrentFocusBoxInType03(zData["ZoneCoordinate"],zData["EffectArea"],zData["EffectColorBox"],zData["EffectPath"],zData["MatchVal"])            elif zType == 4:                focus_box = self.findCurrentFocusBoxInType04(                    zData["ZoneCoordinate"],                    zData["ZoneThreshold"],                    zData["ZoneMaxThreshold"],                    bInside,                    zData["RenderingsMinGirth"],                    zData["RenderingsMaxGirth"],                    zData["RenderingsMinArea"],                    zData["RenderingsMaxArea"])[0]            elif zType == 5:                focus_box = self.findCurrentFocusBoxInType05(                    zData["ZoneCoordinate"],                    zData["focusPicDir"])            elif zType == 6:                focus_box = self.findCurrentFocusBoxInType04(                    zData["ZoneCoordinate"],                    zData["ZoneThreshold"],                    zData["ZoneMaxThreshold"],                    bInside,                    zData["RenderingsMinGirth"],                    zData["RenderingsMaxGirth"],                    zData["RenderingsMinArea"],                    zData["RenderingsMaxArea"])[0]            elif zType == 7:                setting = None                if 'setting' not in zone:                    setting = {"first":["erode",2,2,0,1], "second":["dilate",30,9,0,1],"third":["dilate",24,10,0,2]}                else:                    setting = zone["setting"]                focus_box = self.findCurrentFocusBoxInType06(                     zData["ZoneCoordinate"],                    zData["ZoneThreshold"],                    zData["ZoneMaxThreshold"],                    zData["RenderingsMinGirth"],                    zData["RenderingsMaxGirth"],                    zData["RenderingsMinArea"],                    zData["RenderingsMaxArea"],                    setting)            elif zType == 8:                focus_box = self.findCurrentFocusBoxInType07(                    zData["ZoneCoordinate"],                    zData["ZoneThreshold"],                    zData["ZoneMaxThreshold"],                    bInside,                    zData["RenderingsMinGirth"],                    zData["RenderingsMaxGirth"],                    zData["RenderingsMinArea"],                    zData["RenderingsMaxArea"])            else:                # print u'未使用的焦点类型'                LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:未使用的焦点类型:'+str(zType))            # 找到当前焦点框;            if focus_box is not None:                break        # end-for        if focus_box is None:            return None,None        return focus_box,zName    '''        # 描述:查找当前焦点文本框;        # 参数:        #     'realFocusBox':[x1,y1,x2,y2],   #实际焦点框,坐标系必须是原图左上角;        #     'refTextBox':[x1,y1,x2,y2],     #参考文本框,坐标系必须是原图左上角;        #     'refFocusBox':[x1,y1,x2,y2]     #参考焦点框,坐标系必须是原图左上角;        #     注意:x1,y1,x2,y2分别为矩形左上角(x1,y1)和右下角(x2,y2)        #        # 返回:当前焦点文本框坐标        #         # '''    def findCurrentFocusTextBox(self, realFocusBox, refFocusBox, refTextBox):        return self.getObjAbsoluteBox(realFocusBox, refFocusBox, refTextBox)    '''        # 描述:根据参照物的相对坐标,来获取对象的绝对坐标值;        # 参数:        #   参照对象实际坐标        #   参照对象参照坐标        #   目标对象参照坐标        #         #  '''    def getObjAbsoluteBox(self, refObjRealBox, refObjRefBox, tagObjRefBox):        if refObjRealBox is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:焦点框None,无法计算文本框坐标')            return None        # 目标区域的宽、高;        txWidth, txHeight = tagObjRefBox[2]-tagObjRefBox[0], tagObjRefBox[3]-tagObjRefBox[1]        # 以参照物作为新的坐标系,计算目标区域的相对原点(left,top)        left,top = tagObjRefBox[0]-refObjRefBox[0], tagObjRefBox[1]-refObjRefBox[1]        # 目标对象的绝对原点坐标;        left += refObjRealBox[0]        top += refObjRealBox[1]                # 返回目标对象绝对坐标;        return [left, top, left+txWidth, top+txHeight]    '''        # 描述:获取焦点文本内容;        # 参数:        #   img_or_path:可以是cv2.imread()对象,也可以是图片路径;        #   textBox:[x1,y1,x2,y2]        #   orcInfo: ['language',10001,{}]    # language, ocrType, imgProcParams        # '''    def getCurrentFocusText(self, img_or_path, textBox, orcInfo):        if textBox is None or list(textBox) == list([-1,-1,-1,-1]):            return None        tx_img = None        # 保存截图;        if type(img_or_path) == type(list()):#如果传递的对象;            tx_img = image_util.cutImage(img_or_path, textBox)        elif type(img_or_path) == type(str()):#如果传递的是路径;            imgObj = cv.imread(img_or_path)            tx_img = image_util.cutMat(imgObj, textBox)                if tx_img is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:裁剪图片失败')            return ''        tx_img_path = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"fotx_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")        cv.imwrite(tx_img_path, tx_img)        # orc识别;        text = ''        if len(orcInfo) >= 3 and orcInfo[2] <> {}:            text = self.OCR.getStrWithImgProcess(tx_img_path, orcInfo[2], orcInfo[0], orcInfo[1]).replace(' ','')        else:            text = self.OCR.getStr(tx_img_path, orcInfo[0], orcInfo[1]).replace(' ','')                # 返回文本;        LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:文字识别结果:'+str(text))        return text    '''        # 描述:到达目标区域,成功到达返回True,否则False。        #         #         # '''    def reachTargetZone(self, dictZoneInfo):        if len(dictZoneInfo) == 0:            return None                # 目标区域名称;        destZoneName = dictZoneInfo["destZoneName"]        # 排序dict;        listdict = dictZoneInfo["zoneList"]        for i in range(len(listdict)-1):            for j in range(0, len(listdict)-i-1):                if listdict[j]["zone_priority"] > listdict[j+1]["zone_priority"]:                    listdict[j], listdict[j+1] = listdict[j+1], listdict[j]            # 遍历区域,查找当前焦点所在区域;        focus_box,zName = self.findCurrentFocusBox(listdict)        # 没有找到当前焦点框;        if focus_box is None:            return False        # 当前焦点在目标区域;        if str(zName) == destZoneName:            return True                # 找到目标区域坐标;        zoneBox = []        for zone in dictZoneInfo["zoneList"]:            if destZoneName == str(zone["zoneName"]):                if zone["zoneType"] == 3:                    zoneBox = zone["zoneData"]["zone_area"]                else:                    zoneBox = zone["zoneData"]["ZoneCoordinate"]                break        times = 100        while str(zName) != str(destZoneName):            # 查找目标区域;            retVal = self.getOrientationEx(focus_box, zoneBox)            if retVal == 0: # 左上方;                self.redRat3.sendKey('down')                self.redRat3.sendKey('right')            elif retVal == 1: #正上方;                self.redRat3.sendKey('down')            elif retVal == 2: #右上方;                self.redRat3.sendKey('down')                self.redRat3.sendKey('left')            elif retVal == 3: #正左方;                self.redRat3.sendKey('right')            elif retVal == 4: #正右方;                self.redRat3.sendKey('left')            elif retVal == 5: #左下方;                self.redRat3.sendKey('up')                self.redRat3.sendKey('right')            elif retVal == 6: #正下方;                self.redRat3.sendKey('up')            elif retVal == 7: #右下方                self.redRat3.sendKey('up')                self.redRat3.sendKey('left')            times -= 1            if times <= 0:                break                        focus_box, zName = self.findCurrentFocusBox(listdict)            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:当前焦点区域:'+str(zName)+',目标Zone:'+str(destZoneName))            if focus_box is None:                LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:failed=>当前焦点区域空')                break            # print '结果:'.encode('gbk'),zName.encode('gbk'),destZoneName.encode('gbk')                return True if zName == destZoneName else False            '''        # 描述:获取灰阶二值化图像对象;        # 参数:        #   tvShotPath 图片路径;        #   cropArea 裁剪区域        #   grayVal、maxGrayVal 灰度值和最大灰度值        #   thresholdType 阀值类型,0=全局阀值,1=otsu阀值,2=自适应阀值;        #         # '''    def getBinaryImage(self, tvShotPath, cropArea, grayVal, maxGrayVal, thresholdType = 0):        # 判断文件是否存在;        if os.path.exists(tvShotPath) == False:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片路径不存在'+tvShotPath)            return None                # 打开图片;        img_tvShot = cv.imread(tvShotPath)        if img_tvShot is None:            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:图片对象空')            return None                # 只保留区域部分;        try:            img_crop = np.array(img_tvShot[cropArea[1]:cropArea[3], cropArea[0]:cropArea[2]])        except:            img_crop = img_tvShot        cv.imwrite(LoggingUtil.getCaseRunLogDirPath() + "crop_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png", img_crop)        # 判断对象有效性;        if img_crop is None:            # print u'效果图对象空,可能文件路径无效'            LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:区域截图对象空,可能文件路径无效')            return None                        # 将截图转成灰阶;        img_gray = cv.cvtColor(img_crop, cv.COLOR_BGR2GRAY)        # 高斯模糊;        img_gray = cv.GaussianBlur(img_gray, (3, 3), 0)        # 将灰阶转成二值化图像;        img_binary = None        if thresholdType == 0:            img_binary = cv.threshold(img_gray, grayVal, maxGrayVal, cv.THRESH_BINARY)[1]        elif thresholdType == 1:            img_binary = cv.threshold(img_gray, 0, maxGrayVal, cv.THRESH_BINARY+cv.THRESH_OTSU)[1]        elif thresholdType == 2:            img_binary = cv.medianBlur(img_gray, (3,3))            # bloksize、C两参数,暂时固定为3、4            img_binary = cv.adaptiveThreshold(img_binary, maxGrayVal, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 3, 4.5)        cv.imwrite(LoggingUtil.getCaseRunLogDirPath() + "binary_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png", img_binary)        return img_binary    '''         # 描述:获取滑块轮廓;        #         #         #         #         # '''    def getSilderCountor(self, tvShotPath, cropArea, grayVal, maxGrayVal, bInside, minPeri, maxPeri, minArea, maxArea, morphology, find_1st = True):        # 获取灰阶二值化图片对象;        img_binary = self.getBinaryImage(tvShotPath, cropArea, grayVal, maxGrayVal)        if img_binary is None:            print u'binary is none'            return None                # 对二值化图像进行腐蚀或膨胀操作--形态学;        for val in morphology:            ksize = tuple(val[1:3])            kernel = cv.getStructuringElement(val[3], ksize)            # if val[0] == 0: # 腐蚀;            if val[0] == "erode":                img_binary = cv.erode(img_binary, kernel, val[4])            else:   # 膨胀;                img_binary = cv.dilate(img_binary, kernel, val[4])                morphology_path = LoggingUtil.getCaseRunLogDirPath() + "\\morphology_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png"        cv.imwrite(morphology_path, img_binary)        # 对形态学结果进行轮廓获取;        # 获取二值化图像的轮廓;        area, perimeter = 0.0, 0.0        if bInside == False:#外轮廓            contours = cv.findContours(img_binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[1]        else:#内轮廓            contours = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)[1]                listBox = []        # 过滤掉不符合要求的轮廓;        x, y, w, h,result = 0,0,0,0,False        for cnt in contours:            # 面积;            area = cv.contourArea(cnt)            # 周长;            perimeter = cv.arcLength(cnt, True)            # 获取满足条件的值;            if area >= minArea and area <= maxArea and perimeter >= minPeri and perimeter <= maxPeri:                # 直边矩形,(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高;                x, y, w, h = cv.boundingRect(cnt)                # print u'boundingRect=',x,y,w,h                LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:当前找到的轮廓='+str((x,y,w,h)))                # 在区域内截图判断;                x = x + cropArea[0]                y = y + cropArea[1]                contourRect = [x,y,x+w,y+h]                # 如果只找第一个;                if find_1st == True:                    result = True                    break                # 多个;                listBox.append(contourRect)            #endif        #endfor                # 只返回满足条件的第一个值;        if find_1st == True:            return contourRect if result == True else None        else:            return listBox    #end    '''        # 描述:用Type9到达指定的焦点框        # 参数:        # targetText: 目标焦点框文本        # focusArg: Type9焦点识别参数        # 返回:成功到达焦点框返回True,失败返回False        #         # '''    def reachTargetFocusBoxInType9(self, targetText, focusArg):        # 参数;        loop = focusArg['loop']               cropArea = focusArg['ZoneCoordinate']        grayVal = focusArg['ZoneThreshold']        maxGrayVal = focusArg['ZoneMaxThreshold']        bInside = focusArg['InsideContours']        minPeri = focusArg['focusBoxMinPeri']        maxPeri = focusArg['focusBoxMaxPeri']        minArea = focusArg['focusBoxMinArea']        maxArea = focusArg['focusBoxMaxArea']        refFocusBox = focusArg['RenderingsArea']        refTextBox = focusArg['RenderingsTextArea']        ctrldir = focusArg['FocusDirection']#只有左右=0, 上下=1,混合=2。        # 兼容focus_direction;        if ctrldir == 1 or ctrldir == 2:            ctrldir = 1        elif ctrldir == 3 or ctrldir == 4:            ctrldir = 0        keys = [['left','right'],['up','down']]        def reachType9TargetFocusBox(ctrlkey):            keyCount = 0            ret = False            lastText = ''            firstText = None            sametimes = 0            while True:                # 获取焦点框;                curFocusBox,tvShotPath = self.findCurrentFocusBoxInType04(cropArea,grayVal,maxGrayVal,bInside,minPeri,maxPeri,minArea,maxArea)                if curFocusBox is None:                    LoggingUtil.getDebugLogger().info(pyFileName, self.className, get_current_function_name(), 'SDK:找不到当前焦点')                    break                # 获取文本框;                textBox = self.getObjAbsoluteBox(curFocusBox, refFocusBox, refTextBox)                ocrImgPath = os.path.join(LoggingUtil.getCaseRunLogDirPath(),"OCR_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png")                image_util.saveCropPic(tvShotPath, ocrImgPath, textBox)                ocr_result, text = self.OCR.findPicStr(targetText, ocrImgPath, refTextBox[4], refTextBox[5], refTextBox[6],refTextBox[7])                        if ocr_result == True:                    ret = True                    break                # 记录第一次文本;                if firstText is None:                    firstText = text                else:                    # 循环列表,同时回到起始位置;                    if loop == True and firstText == text:                        break                # 记录最后次文本;                if lastText != text:                    lastText = text                    if loop == False:                        keyCount += 1                else:                    if loop == False:                        sametimes += 1                            # 如果相同次数超过n次,认为到达底部;                if loop == False and sametimes >= 2:                    break                # 遥控;                self.redRat3.sendKey(ctrlkey)                        # 返回结果;            return ret,keyCount        # 正序查找;        result,keyCount = reachType9TargetFocusBox(keys[ctrldir][1])        if result == False:            if loop == True:                return False                        # 到达起点,再反向开始查找;            self.redRat3.sendKey(keys[ctrldir][0], keyCount)            result = reachType9TargetFocusBox(keys[ctrldir][0])[0]        # 返回文本数组;        return result    def getRGBBinaryImage(self, src_pic, cropArea, bgr, offset=20):        # 读取图片;        img = cv.imread(src_pic)        if img is None:            return None,None        # 如果截图区域空,使用原图大小;        if cropArea is not None or cropArea.__len__() == 0:            cropArea = [0, 0, img.shape[1], img.shape[0]]        img_crop = None        # 只保留区域部分;        try:            img_crop = np.array(img[cropArea[1]:cropArea[3], cropArea[0]:cropArea[2]])        except:            img_crop = img        imgArr = np.asarray(img_crop).astype(np.int16)        bgrArr = np.asarray(bgr).astype(np.int16)        # 矩阵相减;        subImg = imgArr - bgrArr        cv.imwrite(r'E:\\subImg.png', subImg)        # img_RGB = cv.cvtColor(img_crop,cv.COLOR_BGR2RGB)        # imgArr_RGB = np.asarray(img_RGB).astype(np.int16)        # rgb = (bgr[2],bgr[1], bgr[0])        # rgbArr = np.asarray(rgb).astype(np.int16)        # subImg_RGB = imgArr_RGB - rgb        # subImgsum = (subImg + subImg_RGB)        # cv.imwrite(r'E:\\subImgsum.png', subImgsum)        # np.where(condition,x,y)满足条件值改为x,否则为y;        # subImg_wh1 = np.where((subImg<-offset)|(subImg>offset), np.uint8(255), np.uint8(0))        subImg_wh1 = np.where((subImg > -offset) & (subImg < offset), np.uint8(0), np.uint8(255))        cv.imwrite(r'E:\\subImg_wh1.png', subImg_wh1)        # 将图处转成灰阶        img_gray = cv.cvtColor(subImg_wh1, cv.COLOR_BGR2GRAY)        # 反转灰度值,以便适合查找轮廓;        img_gray = np.where((img_gray < -offset) | (img_gray > offset), np.uint8(0), np.uint8(255))        # 高斯模糊;        img_gray = cv.GaussianBlur(img_gray, (3, 5), 0)        # 输出结果图片;        cv.imwrite(r'E:\\img_gray.png', img_gray)        # 使用灰度图求得二值化图;        # thresh = cv.threshold(img_gray, 1, 255, cv.THRESH_OTSU | cv.THRESH_BINARY)[1]        thresh = cv.adaptiveThreshold(img_gray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY_INV,15,10)        cv.imwrite(r'E:\\img_thresh.png', thresh)        # 返回二值化图;        return thresh, cropArea    '''        在传入的图片上,查找指定bgr颜色框矩形区域,返回矩形区域的坐标        :param picPath:图片路径        :param bgr:颜色值        :return rectArea:矩形区域 和区域图片        '''    def findCurrentFoucsByColor(self, picPath, cropArea, bgr, offset=20, minPeri=0, maxPeri=0, minArea=0, maxArea=0, morphology = []):        # 获取rgb二值图;        img_binary, cropArea = self.getRGBBinaryImage(picPath, cropArea, bgr, offset)        if img_binary is None:            return False,None        # 对二值化图像进行腐蚀或膨胀操作--形态学;        for val in morphology:            ksize = tuple(val[1:3])            kernel = cv.getStructuringElement(val[3], ksize)            # 腐蚀;            if val[0] == "erode":                img_binary = cv.erode(img_binary, kernel, val[4])            else:   # 膨胀;                img_binary = cv.dilate(img_binary, kernel, val[4])                morphology_path = LoggingUtil.getCaseRunLogDirPath() + "\\morphology_" + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".png"        cv.imwrite(morphology_path, img_binary)        # 查找符合要求的外轮廓;        # opencv3开始,有3个返回值:img, countours, hierarchy        contours = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)[1]        # 是否查找最大轮廓;        bFindMaxContour = False        # 如果周长、面积都一样,只返回最大轮廓;        if minPeri == maxPeri and minArea == maxArea:            bFindMaxContour = True        contourRect = []        maxContour = None  # 最大轮廓;        tempArea = 0        # 过滤掉不符合要求的轮廓;        x, y, w, h, result = 0, 0, 0, 0, False        for cnt in contours:            # 面积;            area = cv.contourArea(cnt)            # 周长;            perimeter = cv.arcLength(cnt, True)            # print "area=%ld, perimeter=%ld"%(area, perimeter)            if bFindMaxContour == True:                # 获取最大轮廓;                if tempArea < area:                    tempArea = area                    maxContour = cnt            else:                # print area,perimeter                # 获取满足条件的值;                if area >= minArea and area <= maxArea and perimeter >= minPeri and perimeter <= maxPeri:                    # 直边矩形,(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高;                    x, y, w, h = cv.boundingRect(cnt)                    # 在区域内截图判断;                    if cropArea is not None:                        x = x + cropArea[0]                        y = y + cropArea[1]                    contourRect = [x, y, x + w, y + h]                    result = True                    break                # endif        # endfor        if bFindMaxContour == True and maxContour is not None:            result = True            # 最大轮廓的矩形坐标;            x, y, w, h = cv.boundingRect(maxContour)            # 在区域内截图判断;            if cropArea is not None:                x = x + cropArea[0]                y = y + cropArea[1]            contourRect = [x, y, x + w, y + h]        # 只返回结果、轮廓坐标;        return result, contourRect     # 文本颜色作为焦点色:获取文本色所有轮廓,计算最左、最右、最上、最下四坐标;    def findFramelessFocusByColor(self, src_pic, cropArea, bgr, offset=20):        # 获取rgb二值图;        thresh, cropArea = self.getRGBBinaryImage(src_pic, cropArea, bgr, offset)        if thresh is None:            return False,[]        # 查找符合要求的外轮廓;        # opencv3开始,有3个返回值:img, countours, hierarchy        contours = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[1]        # contourRect = []        left, right, top, bottom = 100000,0,100000,0        # 遍历轮廓;        for cnt in contours:            # 面积;            # area = cv.contourArea(cnt)            # 周长;            # perimeter = cv.arcLength(cnt, True)            # 直边矩形,(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高;            x, y, w, h = cv.boundingRect(cnt)            # 在区域内截图判断;            if cropArea is not None:                x = x + cropArea[0]                y = y + cropArea[1]                        if left > x:                left = x            if top > y:                top = y            if right < x + w:                right = x + w            if bottom < y + h:                bottom = y + h        #endfor;        # 是否有效矩形;        if left >= right or top >= bottom:            return False, []        # 返回结果;        return True, [left-3, top-3, right+3, bottom+3]        def testFocusArea():    focusAreaDict = {u'tv': [43, 128, 380, 265], u'media': [43, 648, 380, 785], u'hdmi1': [43, 386, 380, 525], u'hdmi2': [43, 517, 380, 655], u'av': [43, 257, 380, 395]}    focusDict = {        "focus_tv": '{"name":"tv","text_area":[179,210,242,248,"english", 253],"focus_area":[43,128,380,265]}',        "focus_av": '{"name":"av","text_area":[180,339,242,381,"english", 253],"focus_area":[43,257,380,395]}',        "focus_hdmi1": '{"name":"hdmi1","text_area":[156,466,269,510,"english", 2],"focus_area":[43,386,380,525]}',        "focus_hdmi2": '{"name":"hdmi2","text_area":[159,599,265,641,"english", 2],"focus_area":[43,517,380,655]}',        "focus_usb": '{"name":"media","text_area":[160,730,260,771,"english", 2],"focus_area":[43,648,380,785]}'    }    icon = r"res\icon.png"    focus_tv = r"res\focus_tv_focus.png"    focus_av = r"res\focus_av_focus.png"    focus_hdmi1 = r"res\focus_hdmi1_focus.png"    focus_hdmi2 = r"res\focus_hdmi2_focus.png"    focus_usb = r"res\focus_usb_focus.png"    picture = r"res\source.jpg"    fDetect = FeatureDetect()    print fDetect.getFocusArea(icon, picture, focusDict, 10)def testRect():    fDetect = FeatureDetect()    # fDetect.findRectByFile(r"D:\temp-pic\parentlock\channel_lock1.png", "parentLock")    fDetect.findRectByFile(r"D:\temp-pic\parentlock\channel_lock2.png", "parentLock")    # fDetect.findRectByFile(r"D:\temp-pic\parentlock\source_lock1.png", "parentLock")if __name__ == "__main__":    fdetect = FeatureDetect()    if 0:        focusArg = {            "TVShotPath": '',            "ZoneCoordinate": [1204, 0, 1920, 1080],            "InsideContours": False,            "ZoneThreshold": 150,            "ZoneMaxThreshold": 255,            # 选中焦点框的周长、面积;            "focusBoxMinPeri": 50,            "focusBoxMaxPeri": 90,            "focusBoxMinArea": 300,            "focusBoxMaxArea": 500,            # 文本最左边;            "textleft":1260,            # 文本最右边;            "textright":1860,            # 文本在焦点滑块上方多高;            "aboveHeight":80,            "aboveMargin":30,            "morphology":[                ["erode",6,6,0,2],                ["dilate",6,6,0,2]            ]        }        listText = []        for i in range(99):            path = r'Z:\Picture\V27N\CusPicMode\%d.png'%i            img = cv.imread(path)            if img is not None:                countor = fdetect.getSilderCountor(                    path,                     focusArg['ZoneCoordinate'],                    focusArg['ZoneThreshold'],                    focusArg['ZoneMaxThreshold'],                    focusArg['InsideContours'],                    focusArg['focusBoxMinPeri'],                    focusArg['focusBoxMaxPeri'],                    focusArg['focusBoxMinArea'],                    focusArg['focusBoxMaxArea'],                    focusArg['morphology'],                    )                width,height = countor[2]-countor[0],countor[3]-countor[1]                # 文本坐标;                txbox = [focusArg['textleft'], countor[1] - focusArg['aboveHeight'], focusArg['textright'], countor[1] - focusArg['aboveMargin']]                text = fdetect.getCurrentFocusText(path, txbox, ["chineseprc+english",10000])                listText.append(text)                print listText    # findFocusTextByColor测试;    if 0:        src_pic = r'C:\Users\jianfeng1.wang\Pictures\Saved Pictures\img.png'        icon_pic = r'C:\Users\jianfeng1.wang\Pictures\Saved Pictures\icon.png'        iconImg = cv.imread(icon_pic)        # 获取小图平均bgr值;        rgbColor = RGBColor()        bgr = rgbColor.getAvgBGR(iconImg)        print fdetect.findFocusTextByColor(src_pic, [], bgr)
 |