| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 | # -*- coding:utf-8 -*-import os, sys, timeimport inspectimport cv2 as cvimport numpy as npfrom ssat_sdk.utils import LoggingUtilfrom 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
 |