# -*- coding:utf-8 -*- import os, sys, time import inspect import cv2 as cv import numpy as np from ssat_sdk.utils import LoggingUtil from image_util import * class LineUtil(): ''' BGR图片传入,获取直线 ''' 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 = cutMat(img, ableArea) grayMat = cv.cvtColor(targetMat, cv.COLOR_BGR2GRAY) # cv.imshow("gray", grayMat) lines, imageGray = self.getGrayLines(grayMat, lineMinLen,lineMaxLen,ableArea,threshold1,threshold2,apertureSize,lineThreshold) return lines, imageGray def getGrayLines(self, imgGray, lineMinLen = 20, lineMaxLen = 1000, ableArea=None, threshold1=50, threshold2=100, apertureSize=5, lineThreshold = 200): edges = cv.Canny(imgGray, 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.caculateLinLen(line[0]) if lineLen > lineMinLen and lineLen < lineMaxLen: # print "retLine:", line[0] cv.line(imgGray, (x1, y1), (x2, y2), 255, 2) retLines.append(line[0]) # cv.imshow("getLines", imgGray) # cv.waitKey(0) # cv.destroyAllWindows() return retLines, imgGray ''' :param lines: ''' def combineLineList(self, lines, maxDistanse=5): retLines = [] for findex in range(0, lines.__len__() - 1): if (lines[findex] is None): continue tmpLine = lines[findex] for sindex in range(1, lines.__len__()): if (lines[sindex] is None): continue secondLine = lines[sindex] isCombined,tmpLine = self.combine2Line(tmpLine,secondLine, maxDistanse) if (isCombined): lines[sindex] = None retLines.append(tmpLine) return retLines ''' 判断两条线段是否在同一个线段上,是否可以组合成一条线段。 :param line1:[x1, y1, x2, y2],第一条线段,基础线段。 :param line2:[x1, y1, x2, y2],第二条线段,拿来对比合并的线段。 :return 1: bool,是否合并了两条线段。True代表已合并,False代表未合并。 :return 2:[x1, y1, x2, y2],最终得到的线段,True是已合并的线段,False则返回line1 ''' def combine2Line(self, line1, line2, maxDistance): # print "combine2Line,line1,line2:",line1, line2 line1 = self.toOriginLine(line1) line2 = self.toOriginLine(line2) # 1 判断是不是同是竖线或者横线。纵向方向不同,返回False direct1 = self.lineDirect(line1) direct2 = self.lineDirect(line2) if (direct1 <> direct2): return False, line1 # 2 判断两条线段所在直线的平行距离。平行距离太远返回False maxDistance = maxDistance paralDistance = self.getParalDistance(line1, line2, direct1) if (paralDistance > maxDistance): return False, line1 # 3 判断两条线段纵向距离。在纵向上相离,相交,包含,相离太远返回False maxInterval = maxDistance status, interval, lineNear, lineFar = self.getLengthwaysDistance(line1, line2, direct1) if ((status == 1) and (interval > maxInterval)) or (status == -1): return False, line1 # 4 合并相离不远、相交和包含的线段 point1 = lineNear[0],lineNear[1] point2 = self.getMaxPoint([lineNear[2], lineNear[3]],[lineFar[0], lineFar[1]],[lineFar[2], lineFar[3]]) retLine = [-1,-1,-1,-1] if direct1 == 1: retLine[0] = point1[0] retLine[2] = point2[0] retLine[1] = (point1[1] + point2[1])/2 retLine[3] = (point1[1] + point2[1])/2 else: retLine[1] = point1[1] retLine[3] = point2[1] retLine[0] = (point1[0] + point2[0])/2 retLine[2] = (point1[0] + point2[0])/2 return True, retLine ''' 例如:[1002 ,134,1002 , 43] 调整为[1002,43,1002,134] ''' def toOriginLine(self, line): retLine = line if (line[0] + line[1]) > (line[2]+line[3]): retLine = [line[2] , line[3], line[0],line[1]] return retLine def getMaxPoint(self, *pointList): # print "getMaxPoint:",pointList maxPoint = [-1,-1] for point in pointList: if (maxPoint[0] + maxPoint[1]) < (point[0] + point[1]): maxPoint[0] = point[0] maxPoint[1] = point[1] return maxPoint def getMinPoint(self, *pointList): # print "getMinPoint:",pointList minPoint = [10000,10000] for point in pointList: if (minPoint[0] + minPoint[1]) > (point[0] + point[1]): minPoint[0] = point[0] minPoint[1] = point[1] return minPoint ''' 找到所有线段中的最小坐标点和最大坐标点 ''' def getLineMMPoint(self, lineList): minPoint = [10000,10000] maxPoint = [-1,-1] for line in lineList: minPoint = self.getMinPoint(minPoint, (line[0],line[1]), (line[2],line[3])) maxPoint = self.getMaxPoint(maxPoint, (line[0],line[1]), (line[2],line[3])) return minPoint,maxPoint ''' 查看line是水平线段,还是竖直线段,或者其他斜线 :param line1:[x1, y1, x2, y2],线段1 :param line2:[x1, y1, x2, y2],线段2 :param direct:1 代表水平,2代表竖直 :return int:1 代表相离,2 代表相交,3 代表包含, -1 代表识别异常 :return int:相离的距离,-1或者相离实际距离 :return line1: 接近原点的线段 :return line2: 远离原点的线段 ''' def getLengthwaysDistance(self, line1, line2, direct): status = -1 distance = -1 tallLine = line1 shortLine = line2 lineLen1 = self.caculateLinLen(line1) lineLen2 = self.caculateLinLen(line2) if (lineLen1 > lineLen2): tallLine = line1 shortLine = line2 else: tallLine = line2 shortLine = line1 if (direct == 1): if (tallLine[1] < shortLine[1]) and (tallLine[3] < shortLine[1]): status = 1 distance = shortLine[1] - tallLine[3] return status, distance, tallLine, shortLine if (tallLine[1] < shortLine[1]) and (tallLine[3] >= shortLine[1]) and (tallLine[3] < shortLine[3]): status = 2 distance = -1 return status, distance, tallLine, shortLine if (tallLine[1] <= shortLine[1]) and (tallLine[3] >= shortLine[3]): status = 3 distance = -1 return status, distance, tallLine, shortLine if (tallLine[1] > shortLine[1]) and (tallLine[1] <= shortLine[3]) and (tallLine[3] > shortLine[3]): status = 2 distance = -1 return status, distance, shortLine, tallLine if (tallLine[1] > shortLine[3]) and (tallLine[3] > shortLine[3]): status = 1 distance = tallLine[1] - shortLine[3] return status, distance, shortLine, tallLine if (direct == 2): if (tallLine[0] < shortLine[0]) and (tallLine[2] < shortLine[0]): status = 1 distance = shortLine[0] - tallLine[2] return status, distance, tallLine, shortLine if (tallLine[0] < shortLine[0]) and (tallLine[2] >= shortLine[0]) and (tallLine[2] < shortLine[2]): status = 2 distance = -1 return status, distance, tallLine, shortLine if (tallLine[0] <= shortLine[0]) and (tallLine[2] >= shortLine[2]): status = 3 distance = -1 return status, distance, tallLine, shortLine if (tallLine[0] > shortLine[0]) and (tallLine[0] <= shortLine[2]) and (tallLine[2] > shortLine[2]): status = 2 distance = -1 return status, distance, shortLine, tallLine if (tallLine[0] > shortLine[2]) and (tallLine[2] > shortLine[2]): status = 1 distance = tallLine[0] - shortLine[2] return status, distance, shortLine, tallLine return status, distance, shortLine, tallLine ''' 查看line是水平线段,还是竖直线段,或者其他斜线 :param line1:[x1, y1, x2, y2],线段1 :param line2:[x1, y1, x2, y2],线段2 :param direct:1 代表水平,2代表竖直 :return int:1 代表水平,2代表竖直,0代表其他斜线 ''' def getParalDistance(self, line1, line2, direct): if direct == 1: return abs(line1[1] - line2[1]) if direct == 2: return abs(line1[0] - line2[0]) ''' 查看line是水平线段,还是竖直线段,或者其他斜线 :param line:[x1, y1, x2, y2],线段 :return bool:1 代表水平,2代表竖直,0代表其他斜线 ''' def lineDirect(self, line): if (line[0] == line[2]): return 2 elif (line[1] == line[3]): return 1 else: return 0 def caculateLinLen(self, line): dx = abs(line[0] - line[2]) dy = abs(line[1] - line[3]) # print "caculateLinLen:",dx,dy lineLen = np.sqrt(np.square(dx) + np.square(dy)) return lineLen