# -*- coding:utf-8 -*- import os, sys, time from ssat_sdk.device_manage.capturecard_manager import CCardManager from pic_tool import ImageCMP from sound_tool import AudioIdentify from picture.feature_detect import * from ssat_sdk.picture.color_space import CIEluvCaculator from ssat_sdk.sat_environment import * from ocr_convert import OCRConvert from ssat_sdk.picture import image_util from ssat_sdk.pic_tool import ImageCMP import cv2 as cv import thread import threading from ssat_sdk.utils import LoggingUtil from ssat_sdk.TvDetect.colorbar_detect import ColorBarDetect pyFileName = os.path.split(__file__)[-1] def get_current_function_name(): return inspect.stack()[1][3] # 模板匹配全局对象; g_threadMonitor = None g_monitorResult = {} g_stopThread = False class TvDetect(): def __init__(self): self.audioChecker = AudioIdentify() self.vp = VideoCapture() self.featureDetect = FeatureDetect() self.CIECaculator = CIEluvCaculator() self.OCR = OCRConvert() self.className = self.__class__.__name__ self.imageUtil = image_util.ImageUtil() self.imgCMP = ImageCMP() self.colorBarDetect = ColorBarDetect() ''' 检测电视锁屏。自行截取电视画面后检索 :return hasLockStr:是否有锁屏提示字符 :return isBlack:是否全是黑屏,没有画面 :return hasLockStr:是否有锁屏提示字符 ''' def detectLockScreen(self): # lockPic = r"D:\temp-pic\parentlock\channel_lock2.png" # lockPic = r"D:\temp-pic\parentlock\channel_lock1.png" # lockPic = r"D:\temp-pic\parentlock\source_lock1.png" lockPic = os.path.join(getSATTmpDIR(), "lock_screen.png") self.vp.takePicture(lockPic) return self.detectLockPic(lockPic) ''' 检测电视锁屏.根据提供的图片进行检测 :param lockPic:电视画面的图片路径 :return hasLockStr:是否有锁屏提示字符 :return isBlack:是否全是黑屏,没有画面 :return hasLockStr:是否有锁屏提示字符 ''' def detectLockPic(self, lockPic): maxDiff = 5 blackLuv = (11,96,136) hasLockStr = False isBlack = True lockRect = self.featureDetect.findRectByFile(lockPic, "parentLock") print lockRect rectPic = os.path.join(getSATTmpDIR(), "rect.png") image_util.saveCropPic(lockPic, rectPic, lockRect) info = self.OCR.getStr(rectPic, "english", 2) print "detectLockPic,str:",info if info.lower().find("locked") > 0: hasLockStr = True retImgList = image_util.saveRetCropPic(lockPic, lockRect) for index in range(retImgList.__len__()): # cv.imshow(str(index),retImgList[index]) imgLuv = cv.cvtColor(retImgList[index], cv.COLOR_BGR2Luv) l, u, v = self.CIECaculator.getAverageLUV(imgLuv) diffLevel = self.CIECaculator.getDiffuvLevel(blackLuv, (l, u, v)) if (diffLevel > maxDiff): isBlack = False # cv.waitKey(0) # cv.destroyAllWindows() # print hasLockStr, isBlack, lockPic return hasLockStr, isBlack, lockPic ''' 传入电视的重现率检测画面(22293/4 pattern304 或者TG39 mark画面),按像素计算重现率。 :param pic_path:重现率电视画面图片路径 :param scaleGray:刻度与悲剧G枪分界值 :param scaleMax_W:宽,即水平刻度数,不包含图像边界 :param scaleMax_H:高,即垂直刻度数,不包含图像边界 :param scaleUnit_W:宽,水平刻度单位值 :param scaleUnit_H: 高,垂直刻度单位值 :param scaleLineOffset:刻度线段可偏离像素点数 :return 浮点数组。[左边重显率,右边重显率,上边重显率,下边重显率] ''' def detectOverScan(self, pic_path, scaleMax_W=10, scaleMax_H=10, scaleUnit_W=0.02, scaleUnit_H=0.04, scaleLineOffset=3): img = cv.imread(pic_path) img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) h1, w1 = img_gray.shape center_height, center_width = self.findCenterPoint(img_gray) #计算左边重现率 # print "detectOverScan,scale_left" scale_left = self.detectWhiteScale(img_gray, scaleMax_W, scaleUnit_W, (0, center_height-scaleLineOffset), (center_width/3, center_height-scaleLineOffset)) # print "detectOverScan,scale_right" scale_right = self.detectWhiteScale(img_gray, scaleMax_W, scaleUnit_W, (w1-1, center_height-scaleLineOffset), (5*center_width/3, center_height-scaleLineOffset)) # print "detectOverScan,scale_up" scale_up = self.detectWhiteScale(img_gray, scaleMax_H, scaleUnit_H, (center_width-scaleLineOffset, 0), (center_width-scaleLineOffset, center_height/2)) # print "detectOverScan,scale_down" scale_down = self.detectWhiteScale(img_gray, scaleMax_H, scaleUnit_H, (center_width - scaleLineOffset, h1-1), (center_width - scaleLineOffset, 3*center_height / 2)) # print scale_left,scale_right,scale_up,scale_down return scale_left,scale_right,scale_up,scale_down ''' 寻找图片白色条相交中心点,例如:重现率图片 ''' def findCenterPoint(self, img): h1,w1 = img.shape center_x1 = 4 * w1 / 10 center_y1 = 4 * h1 / 10 center_x2 = 6 * w1 / 10 center_y2 = 6 * h1 / 10 # print center_x1, center_y1, center_x2, center_y2 area_center = [center_x1, center_y1, center_x2, center_y2] img_center = image_util.cutMat(img, area_center) h2, w2 = img_center.shape # print h2,w2,dim2 # 寻找中心点的高坐标 line_w = w2 / 20 line_1 = [line_w, h2 / 3, line_w, 2 * h2 / 3] # print "line_1:",line_1 center_height = center_y1 grayAvg1 = self.imageUtil.calGrayAvg(img_center, line_1) # print "grayAvg:",grayAvg1 for height in range(line_1[1], line_1[3]): if img_center[height, line_w] >= grayAvg1: center_height += height break print "center_height:",center_height # 寻找纵向直线的宽坐标 line_h = h2 / 20 line_2 = [w2 / 3, line_h, 2 * w2 / 3, line_h] center_width = center_x1 grayAvg2 = (np.max(line_1) + np.min(line_1)) / 2 for width in range(line_2[0], line_2[2]): if img_center[line_h, width] >= grayAvg2: center_width += width break print "center_width:", center_width return center_height, center_width ''' 判断是否在重显率画面 :param picPath:图片路径 :return True/False:True:是重显率画面,False:不是重显率 ''' def isOverScan(self, picPath): print "isOverScan,picPath:",picPath srcImg = cv.imread(picPath) height,widht,dim = srcImg.shape grayImg = cv.cvtColor(srcImg,cv.COLOR_BGR2GRAY) center_height, center_width = self.findCenterPoint(grayImg) dHeight = center_height*2.0/height dWidth = center_width*2.0/widht if 0.98 < dHeight < 1.02 and 0.98 < dWidth < 1.02: return True else: return False ''' 根据指定的直线,扫描刻度线条。去掉刻度线条宽度的影响,同时刻度线条和背景灰阶阈值,采用像素点平均值。 :param img:待检测图片。22293 pattern :param scaleLevel:刻度等级数,即多少条刻度线.刻度线不包含图像边界线。 :param scaleUnit: 每一个刻度,读数值 :param pointStart:刻度起始点坐标。 width-x,height-y坐标系 :param pointEnd: 刻度重点坐标。 width-x,height-y坐标系 :return 重显率scaleDG:取值范围 0.00 ~ 1.00 ''' def detectWhiteScale(self, img, scaleLevel, scaleUnit, pointStart, pointEnd, grayMidOffset = 50): grayMid = self.imageUtil.calGrayAvg(img, (pointStart[0],pointStart[1], pointEnd[0],pointEnd[1])) + grayMidOffset print "detectWhiteScale:pointStart:pointEnd:grayMid:",(pointStart,pointEnd, grayMid) scalePointList = [] w_list,h_list = self.genPointHWArray(pointStart,pointEnd) selPoint = None prevPoint = (w_list[0], h_list[0]) for height in h_list: for width in w_list: # print img[prevPoint[1], prevPoint[0]] , img[height,width] if img[height,width] > grayMid: if selPoint is None or \ (int(img[prevPoint[1], prevPoint[0]]) <= grayMid and image_util.caculateLinLen((selPoint[0],selPoint[1],width,height)) > 5): # 每条刻度的宽度像素点不定,取刻度的第一个像素点,作为刻度坐标 selPoint = (width,height) scalePointList.append(selPoint) prevPoint = (width,height) print u"刻度点列表:", scalePointList if scalePointList.__len__() < 2: print u"重显率检测失败,刻度点列表:", scalePointList return -1.0 x1,y1 = scalePointList[0] x2,y2 = scalePointList[1] step = image_util.caculateLinLen((x1,y1, x2,y2)) # print "detectWhiteScale step:", step hintLevel = scaleLevel - scalePointList.__len__() # print "detectWhiteScale hintLevel:",hintLevel # direction = self.featureDetect.lineUtil.lineDirect((x1,y1, x2,y2)) oneLevel = (step - (image_util.caculateLinLen((x1,y1,pointStart[0],pointStart[1]))))/step # print "detectWhiteScale oneLevel:",oneLevel scaleDG = 1 - (hintLevel*scaleUnit + oneLevel*scaleUnit) # print "detectWhiteScale scaleDG:",scaleDG return scaleDG ''' 将坐标全部存入数组,解决坐标从小到大和从大到小均可遍历问题。 ''' def genPointHWArray(self, pointStart, pointEnd): w1 = pointStart[0] h1 = pointStart[1] w2 = pointEnd[0] h2 = pointEnd[1] w_list = [] h_list = [] if w1 >= w2: for dw in range(0, w1-w2+1): w_list.append(w1-dw) else: for w in range(w1, w2+1): w_list.append(w) if h1 >= h2: for dh in range(0, h1-h2+1): h_list.append(h1-dh) else: for h in range(h1, h2+1): h_list.append(h) # print "w_list:",w_list # print "h_list:",h_list return w_list,h_list ''' 监听视频,查看是否会中途无声无像 :param 要监听时间长度。单位秒。 :param 要监听的画面,标准:0 代表黑屏,1 代表有画面 :param galleryDir.指定窗口样图路径,有代表需要监听,没有代表不需要监听 :param blackTh: 黑色图片判断阈值,低于或等于则表示为黑色。默认50 :return 两个数组:SoundExpList,VideoExpList。 list的格式:数组内存放字典。字典{"time":time.asctime( time.localtime(time.time()))}。 List里面的第一个time值,表示开始监听的时间。 SoundExpList第一个字典数据,有audio 键,取录音文件路径。status键:0 代表无异常;1代表没有声音发出;2代表声音有间断。 VideoExpList每一个异常字典数据,有picture键,取图片。第一个字典数据中,status键:0 代表一直有画面;1代表一直黑屏;2代表有黑屏出现,-1代表截图失败。 第一个字典数据中,motion_picture:1 代表运动画面,0 代表静态画面。 ''' def monitorVideo(self, seconds = 10, galleryDir = "", picTarget=1, blackTh = 50): soundExpList = [] soundTID = thread.start_new_thread(self.audioChecker.monitorSound, (seconds, soundExpList)) pictureExpList = [] picTID = thread.start_new_thread(self.monitorTvPicture, (seconds,pictureExpList, picTarget, blackTh)) global g_monitorResult if os.path.exists(unicode(galleryDir)) == True: self.startMonitorAbnormal(seconds, galleryDir) count = 0 while soundExpList.__len__() < 1 or pictureExpList.__len__() < 1: print "monitorVideo ...seconds:",count time.sleep(1) count += 1 # print "monitorVideo, abnormal:",g_monitorResult # 为保持向前兼容,g_monitorResult结果单独使用getMonitorAbnormalResults获取 return soundExpList,pictureExpList#,g_monitorResult def monitorTvPicture(self,seconds, expList, picTarget=1, blackTh = 50): hasImage = False startSeconds = time.time() expList.append({"time": time.asctime(time.localtime(startSeconds)),"picture":"", "status":0}) expList[0]["motion_picture"] = 0 #默认为静态画面 curSeconds = time.time() prevPic = os.path.join(getSATTmpDIR(), "monitorTvPicture" + str(time.time()) + ".png") self.vp.takePicture(prevPic) LoggingUtil.printLog("Record picture...") while (curSeconds - startSeconds) < seconds: currentPic = os.path.join(getSATTmpDIR(), "monitorTvPicture"+str(time.time())+".png") self.vp.takePicture(currentPic) # 加0.5秒延时,防止截图过快导致异常 time.sleep(0.5) curSeconds = time.time() try: #检测画面是否纯黑色背景 if picTarget == 1:#黑屏无画面,异常 if (self.imgCMP.isBlack(currentPic)): expList.append({"time":time.asctime(time.localtime(curSeconds)),"picture":currentPic}) else: hasImage = True else: #黑屏无画面,正常 if (self.imgCMP.isBlack(currentPic, blackTh)): pass else: expList.append({"time":time.asctime(time.localtime(curSeconds)),"picture":currentPic}) hasImage = True except Exception,e: # 未能正常截到图,导致测试失败 LoggingUtil.printLog(u"monitorTvPicture截图失败!!!\nErrorMsg:%s\ncurrentPic路径:%s\n"%(e,currentPic)) expList[0]["status"] = -1 return #检测画面是动态还是静态 if self.imgCMP.cmpPicTotal(prevPic, currentPic, expDotRate=0) is False: expList[0]["motion_picture"] = 1 prevPic = currentPic LoggingUtil.printLog("Record picture End") if hasImage and expList.__len__() == 1: expList[0]["status"] = 0 elif hasImage and expList.__len__() > 1: expList[0]["status"] = 2 else: expList[0]["status"] = 1 ''' # 描述:监控异常 # 参数: # seconds:监控时长. # galleryDir:图库目录路径 # 返回:bool, fileAbnormal, coordinate,fileTV # True:有异常,False:正常 # fileAbnormal:异常时,与异常匹配的图库文件路径 # coordinate:异常时,异常框的坐标。 # fileTV:出现异常的视频截图路径。 # ''' def monitorAbnormal(self, seconds, galleryDir): pic_path = "" result = {"result": False, "tmpVal":0, "galleryFile":"", "coordinate":[0,0,0,0]} setting = {'method':5, 'colorType':0, 'thresholdVal':0, 'thresholdMaxVal':255} #可从配置文件读取,不用从参数传入 global g_stopThread startSeconds = time.time() while g_stopThread == False: # 一秒截一图; pic_path = os.path.join(getAbnormalDir(), time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))+".png") self.vp.takePicture(pic_path) # 异常匹配; result = self.featureDetect.matchImage(pic_path, None, galleryDir, setting) if result["result"] == True: result["screenFile"] = pic_path break # 删除无异常的截图; os.remove(pic_path) # 超时退出线程; if int(time.time() - startSeconds) > seconds: break # 返回全局对象; if result["result"] == False: result["screenFile"] = "" global g_monitorResult g_monitorResult = result print u'异常监控结果:',g_monitorResult["result"],g_monitorResult["tmpVal"],g_monitorResult["coordinate"],g_monitorResult["screenFile"].encode('gb2312'),g_monitorResult["galleryFile"].encode('gb2312') # 启动监控线程; def startMonitorAbnormal(self, seconds, galleryDir): global g_threadMonitor,g_stopThread if g_threadMonitor is not None and g_threadMonitor.is_alive() == True: print u'线程已运行' return g_stopThread = False g_threadMonitor = threading.Thread(target=self.monitorAbnormal, name='MonitorAbnormal', args=(seconds,galleryDir)) g_threadMonitor.start() # 停止监控; def stopMonitorAbnormal(self): global g_threadMonitor,g_stopThread if g_threadMonitor is not None and g_threadMonitor.is_alive() == True: g_stopThread = True print u'开始停止' else: print u'线程已停止' ''' # 描述:获取监控结果 # # ''' def getMonitorAbnormalResults(self): global g_monitorResult return g_monitorResult ''' HDMI重显率测试:1080P及以上分辨率重显率为100%;1080P分辨率以下重显率为95%-97%,显示器模式时为100%. 片源 22294: pattern:304 根据传入的图片和重显率要求,返回检测结果。 重现率最小界限,增加0.01容错。两边偏移不超过0.02 :param picPath: 电视截图路径 :param resolution: "Full":全屏显示。 "HD":高清, "SD":标清 :param offsetMax = 0.02#中心点偏移的容错值 :param downTh = 0.01#重现率偏小的容错值 :return :两个参数。参数1 True或者False,参数2, 具体结果参数数组。 ''' def detectHDMIOverScan(self, picPath, resolution="", STD=[],offsetMax = 0.02, downTh = 0): print "detectHDMIOverScan:", picPath, resolution if STD == []: hdmiRSTD = {"full":[1.0,1.0], "hd":[1.0,1.0], "sd":[0.95,0.97]} STD = hdmiRSTD[resolution.lower()] left, right, up, down = self.detectOverScan(picPath) # print "detectHDMIOverScan,left, right, up, down:", left, right, up, down hOverscan, hOffset = self.calOverScan(left,right) vOverscan, vOffset = self.calOverScan(up,down) if hOverscan + downTh >= STD[0] and hOverscan <= STD[1] and hOffset < offsetMax\ and (vOverscan + downTh) >= STD[0] and vOverscan <= STD[1] and vOffset < offsetMax: return True, [resolution, STD, [(hOverscan,hOffset), (vOverscan,vOffset)]] else: return False, [resolution, STD, [(hOverscan,hOffset), (vOverscan,vOffset)]] def calOverScan(self, side1, side2): scale = (side1+side2)/2 return round(scale, 3), round(abs(side1-side2),3) ''' AV重显率测试:重显率为95%-97% 片源 22294: pattern:304 重现率最小界限,增加0.01容错。两边偏移不超过0.02 根据传入的图片和重显率要求,返回检测结果。 :param picPath: 电视截图路径 :param offsetMax = 0.02#中心点偏移的容错值 :param downTh = 0.01#重现率偏小的容错值 :return :两个参数。参数1 True或者False,参数2, 具体结果参数数组。 ''' def detectAVOverScan(self, picPath, STD = [0.95,0.97], offsetMax = 0.02, downTh = 0): print "detectAVOverScan:", picPath left, right, up, down = self.detectOverScan(picPath) # print "detectAVOverScan,left, right, up, down:", left, right, up, down hOverscan, hOffset = self.calOverScan(left,right) vOverscan, vOffset = self.calOverScan(up,down) if hOverscan+downTh >= STD[0] and vOverscan <= STD[1] and hOffset < offsetMax\ and hOverscan+downTh >= STD[0] and vOverscan <= STD[1] and vOffset < offsetMax: return True, [STD, [(hOverscan, hOffset), (vOverscan, vOffset)]] else: return False, [STD, [(hOverscan, hOffset), (vOverscan, vOffset)]] ''' ATV重显率(重现率要求95%-97%之间,(行6.5-7,帧5-6) 片源 检测片源TG39 mark 根据传入的图片和重显率要求,返回检测结果。 重现率最小界限,增加0.01容错。两边偏移不超过0.02 :param picPath: 电视截图路径 :param offsetMax = 0.02#中心点偏移的容错值 :param downTh = 0.01#重现率偏小的容错值 :return :两个参数。参数1 True或者False,参数2, 具体结果参数数组。 ''' def detectAtvOverScan(self, picPath, STD = [0.95, 0.97], offsetMax = 0.02, downTh = 0): print "detectAtvOverScan:", picPath left, right, up, down = self.detectOverScan(picPath, scaleMax_W=4, scaleMax_H=5, scaleUnit_W=0.05, scaleUnit_H=0.05, scaleLineOffset=5) # print "detectAtvOverScan,left, right, up, down:", left, right, up, down hOverscan, hOffset = self.calOverScan(left,right) vOverscan, vOffset = self.calOverScan(up,down) if (hOverscan + downTh) >= STD[0] and hOverscan <= STD[1] and hOffset < offsetMax \ and (vOverscan + downTh) >= STD[0] and vOverscan <= STD[1] and vOffset < offsetMax: return True, [STD, [(hOverscan, hOffset), (vOverscan, vOffset)]] else: return False, [STD, [(hOverscan, hOffset), (vOverscan, vOffset)]] def detectAtv3116OverScan(self, picPath, STD = [0.95, 0.97], offsetMax = 0.02, downTh = 0): print "detectAtv3116OverScan:", picPath left, right, up, down = self.detectOverScan(picPath, scaleMax_W=4, scaleMax_H=3, scaleUnit_W=0.05, scaleUnit_H=0.05, scaleLineOffset=5) # print "detectAtvOverScan,left, right, up, down:", left, right, up, down hOverscan, hOffset = self.calOverScan(left, right) vOverscan, vOffset = self.calOverScan(up, down) if (hOverscan + downTh) >= STD[0] and hOverscan <= STD[1] and hOffset < offsetMax \ and (vOverscan + downTh) >= STD[0] and vOverscan <= STD[1] and vOffset < offsetMax: return True, [STD, [(hOverscan, hOffset), (vOverscan, vOffset)]] else: return False, [STD, [(hOverscan, hOffset), (vOverscan, vOffset)]] ''' 假定重现率正确 检测画面:TG39 网格 根据传入的网格图片,判断比例模式是否正确。 :param mode: "full", origin, smart, zoom :param testPic: 图片路径 :return :1个参数。参数1 True或者False ''' def detectATVAspectRatio(self, testPic, mode): scale_W = 17.0 scale_H = 13.0 widthRatio = 0 heightRatio = 0 if mode == "full": widthRatio = 1.0 heightRatio = 1.0 elif mode == "origin": widthRatio = 1.0 heightRatio = 0 elif mode == "smart": widthRatio = 1.0 heightRatio = 11/scale_H elif mode == "zoom": widthRatio = 1.0 heightRatio= 9/scale_H else: pass return self.detectAspectRatio(testPic, scale_W, scale_H,widthRatio,heightRatio) ''' 假定重现率正确 检测画面:22294 Timing65 Pattern55 根据传入的网格图片,判断比例模式是否正确。 :param mode: "full", origin, smart, zoom :param testPic: 图片路径 :return :1个参数。参数1 True或者False ''' def detectHDMIAspectRatio(self, testPic, mode): scale_W = 15.0 scale_H = 11.0 widthRatio = 0 heightRatio = 0 if mode == "full": widthRatio = 1.0 heightRatio = 1.0 elif mode == "origin": widthRatio = 1.0 heightRatio = 0 elif mode == "smart": widthRatio = 1.0 heightRatio = 11 / scale_H elif mode == "zoom": widthRatio = 1.0 heightRatio = 9 / scale_H else: pass return self.detectAspectRatio(testPic, scale_W, scale_H,widthRatio,heightRatio) ''' 假定重显率正确 检测画面:22294 Timing36 Pattern55 根据传入的网格图片,判断比例模式是否正确。 :param mode: "full", origin, smart, zoom :param testPic: 图片路径 :return :1个参数。参数1 True或者False ''' def detectAVAspectRatio(self, testPic, mode): return self.detectHDMIAspectRatio(testPic,mode) ''' 根据传入的网格图片,判断比例模式是否正确。 :param mode: "full", origin, smart, zoom :param testPic: 图片路径 :param scale_W:水平宽的网格线数量 :param scale_H:垂直高的网格线数量 :param widthRatio:相比于origin,水平宽的比例要求 :param heightRatio:相比于origin,垂直高的比例要求 :param scaleGray:网格黑色背景和白色刻度线的G枪分界线 :return :1个参数。参数1 True或者False ''' def detectAspectRatio(self, testPic, scale_W, scale_H, widthRatio, heightRatio,scaleGray=80): print "detectAspectRatio:", scale_W, scale_H img = cv.imread(testPic) height, width, color =img.shape scalePointListW = self.getScaleNumber(img, (0,5), (width-1, 5), scaleGray) print "detectAspectRatio,scalePointListW:",scalePointListW.__len__(),scalePointListW scalePointListH = self.getScaleNumber(img, (5,0), (5, height-1), scaleGray) print "detectAspectRatio,scalePointListH:",scalePointListH.__len__(),scalePointListH # print "detectAspectRatio:",scalePointListW.__len__() /scale_W,widthRatio,scalePointListH.__len__() / scale_H,heightRatio if scalePointListW.__len__() /scale_W == widthRatio\ and scalePointListH.__len__() / scale_H == heightRatio: return True else: return False def getScaleNumber(self, img,pointStart,pointEnd, scaleGray): # print "getScaleNumber:", pointStart, pointEnd scalePointList = [] w_list, h_list = self.genPointHWArray(pointStart, pointEnd) selPoint = None prevPoint = (w_list[0], h_list[0]) for height in h_list: for width in w_list: # print img[prevPoint[1], prevPoint[0]][1] , img[height,width][1],prevPoint[1], prevPoint[0] if img[height, width][1] > scaleGray: if selPoint is None or \ int(img[prevPoint[1], prevPoint[0]][1]) <= scaleGray: # 每条刻度的宽度像素点不定,取刻度的第一个像素点,作为刻度坐标 selPoint = (width, height) scalePointList.append(selPoint) prevPoint = (width, height) return scalePointList ''' 检测电视是否已经关机 检测方式:1 检测画面是否有变化;检测连续5张截图,均没有变化,且四个角落为相同纯色,且没有声音,则表示处于关机状态。 声音检测和纯色检测,可选。 :param : checkSignle:选择是否要检测四周纯色。 :param :checkAudio : 是否要检测无声。 :param : colorOffset : 颜色允许的偏移量 :param : expDotRate : 异常点比例范围上限.前后两张图片差分时的差异点比例。 :return : [检测结果,[图片地址列表], [音频地址列表]] ''' def detectPowerOff(self, checkSignle=True, checkAudio=True, colorOffset=20, expDotRate = 0.0001): picList = [] soundList = [] ccard= CCardManager() count = 0 matchCount = 0 previewPic = os.path.join(getSATTmpDIR(), "detectPowerOff_"+str(time.time())+".png") ccard.takePicture(previewPic) picList.append(previewPic) while count < 5: currentPic = os.path.join(getSATTmpDIR(), "detectPowerOff_"+str(time.time())+".png") ret = ccard.takePicture(currentPic) print "detectPowerOff,截图:",ret if ret == 1: count += 1 ret1 = self.imgCMP.cmpPicTotal(previewPic, currentPic, colorOffset, expDotRate) print "detectPowerOff,前后图片比对:",ret1 #检测4个角落纯色 if checkSignle is True: ret2 = self.imgCMP.checkAroundSSColor(currentPic) print "detectPowerOff,四周相同纯色:", ret2 else: ret2= True if ret1 and ret2: matchCount += 1 previewPic = currentPic picList.append(currentPic) if matchCount < 5: return False, picList, soundList #检测声音 if checkAudio is True: self.audioChecker.startCHK(5) soundList.append(self.audioChecker.audioFile) return not self.audioChecker.isOK(), picList, soundList else: return True, picList, soundList def isColorBar(self, picPath, type): if type.lower()=="hdmi" or type.lower()=="dtv": return self.colorBarDetect.isHDMIColorBar(picPath) elif type.lower()=="av": return self.colorBarDetect.isAVColorBar(picPath) elif type.lower()=="atv": return self.colorBarDetect.isATVColorBar(picPath) else: return False if __name__ == "__main__": tvDetect = TvDetect() # pic = "D:/test/4k2.jpg" pic = "D:/test/colorbar_hdmi_std.png" ret = tvDetect.isColorBar(pic,"hdmi") print "isColorBar HDMI:",ret ret = tvDetect.isColorBar(pic,"dtv") print "isColorBar DTV:",ret ret = tvDetect.isColorBar(pic,"av") print "isColorBar AV:",ret ret = tvDetect.isColorBar(pic,"atv") print "isColorBar ATV:",ret # print "detectHDMIOverScan:", tvDetect.detectHDMIOverScan(pic,"full") # lockPic = r"D:\temp-pic\parentlock\unlockChannel_channelLock.jpg" # lockPic = r"D:\temp-pic\parentlock\unlockTV_image.jpg" # lockPic = r"D:\temp-pic\parentlock\inputLock_image.jpg" # print tvDetect.detectLockPic(lockPic) # print tvDetect.monitorVideo(500) # time.sleep(2) # print tvDetect.startMonitorAbnormal(1000, r'C:\Users\jianfeng1.wang\Pictures\图库') # print tvDetect.startMonitorAbnormal(10, r'C:\Users\jianfeng1.wang\Pictures\图库') # time.sleep(10) # tvDetect.stopMonitorAbnormal() # time.sleep(11) # print tvDetect.startMonitorAbnormal(10, r'C:\Users\jianfeng1.wang\Pictures\图库')