12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320 |
- # -*- coding:utf-8 -*-
- import inspect
- import os, sys, time
- '''
- 用于图片特征提取和定位
- '''
- import image_util
- import PreImageJudge
- import cv2 as cv
- import numpy as np
- import json
- from ssat_sdk.sat_environment import *
- from TST.NetOCR import *
- from ssat_sdk.ocr_convert import *
- from color_space import *
- from line_util import LineUtil
- from ssat_sdk.device_manage import *
- # 导入枚举;
- from enum import Enum
- from itertools import chain
- # from ssat_sdk.device_manage.RedRatHub3 import RedRat3
- from ssat_sdk.tv_operator import *
- from ssat_sdk.video_capture import VideoCapture
- # import ssat_sdk.utils.LoggingUtil
- from ssat_sdk.utils import LoggingUtil
- from ssat_sdk.utils import string_util
- from ssat_sdk.picture.RGB import RGBColor
- from ssat_sdk.picture.pq_detect import PQDetect
- pyFileName = 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)
|