123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- # -*- 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
|