line_util.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. # -*- coding:utf-8 -*-
  2. import os, sys, time
  3. import inspect
  4. import cv2 as cv
  5. import numpy as np
  6. from ssat_sdk.utils import LoggingUtil
  7. from image_util import *
  8. class LineUtil():
  9. '''
  10. BGR图片传入,获取直线
  11. '''
  12. def getLines(self, img, lineMinLen = 20, lineMaxLen = 1000, ableArea=None, threshold1=50, threshold2=100, apertureSize=5, lineThreshold = 200):
  13. targetMat = np.array(img)
  14. if (ableArea <> None):
  15. targetMat = cutMat(img, ableArea)
  16. grayMat = cv.cvtColor(targetMat, cv.COLOR_BGR2GRAY)
  17. # cv.imshow("gray", grayMat)
  18. lines, imageGray = self.getGrayLines(grayMat, lineMinLen,lineMaxLen,ableArea,threshold1,threshold2,apertureSize,lineThreshold)
  19. return lines, imageGray
  20. def getGrayLines(self, imgGray, lineMinLen = 20, lineMaxLen = 1000, ableArea=None, threshold1=50, threshold2=100, apertureSize=5, lineThreshold = 200):
  21. edges = cv.Canny(imgGray, threshold1, threshold2, apertureSize=apertureSize)
  22. # cv.imshow("edges",edges)
  23. lines = cv.HoughLinesP(edges, 2, np.pi / 180, lineThreshold)
  24. retLines = []
  25. if lines is None:
  26. return None, None
  27. for line in lines:
  28. x1, y1, x2, y2 = line[0]
  29. # print "line:", x1, y1, x2, y2
  30. # "line rgb:",PreImageJudge.getImgAverageRGB(targetMat, (x1, y1, x2+1, y2+1)), \
  31. # "icon rgb:",PreImageJudge.getAverageRGB(icon)
  32. lineLen = self.caculateLinLen(line[0])
  33. if lineLen > lineMinLen and lineLen < lineMaxLen:
  34. # print "retLine:", line[0]
  35. cv.line(imgGray, (x1, y1), (x2, y2), 255, 2)
  36. retLines.append(line[0])
  37. # cv.imshow("getLines", imgGray)
  38. # cv.waitKey(0)
  39. # cv.destroyAllWindows()
  40. return retLines, imgGray
  41. '''
  42. :param lines:
  43. '''
  44. def combineLineList(self, lines, maxDistanse=5):
  45. retLines = []
  46. for findex in range(0, lines.__len__() - 1):
  47. if (lines[findex] is None):
  48. continue
  49. tmpLine = lines[findex]
  50. for sindex in range(1, lines.__len__()):
  51. if (lines[sindex] is None):
  52. continue
  53. secondLine = lines[sindex]
  54. isCombined,tmpLine = self.combine2Line(tmpLine,secondLine, maxDistanse)
  55. if (isCombined):
  56. lines[sindex] = None
  57. retLines.append(tmpLine)
  58. return retLines
  59. '''
  60. 判断两条线段是否在同一个线段上,是否可以组合成一条线段。
  61. :param line1:[x1, y1, x2, y2],第一条线段,基础线段。
  62. :param line2:[x1, y1, x2, y2],第二条线段,拿来对比合并的线段。
  63. :return 1: bool,是否合并了两条线段。True代表已合并,False代表未合并。
  64. :return 2:[x1, y1, x2, y2],最终得到的线段,True是已合并的线段,False则返回line1
  65. '''
  66. def combine2Line(self, line1, line2, maxDistance):
  67. # print "combine2Line,line1,line2:",line1, line2
  68. line1 = self.toOriginLine(line1)
  69. line2 = self.toOriginLine(line2)
  70. # 1 判断是不是同是竖线或者横线。纵向方向不同,返回False
  71. direct1 = self.lineDirect(line1)
  72. direct2 = self.lineDirect(line2)
  73. if (direct1 <> direct2):
  74. return False, line1
  75. # 2 判断两条线段所在直线的平行距离。平行距离太远返回False
  76. maxDistance = maxDistance
  77. paralDistance = self.getParalDistance(line1, line2, direct1)
  78. if (paralDistance > maxDistance):
  79. return False, line1
  80. # 3 判断两条线段纵向距离。在纵向上相离,相交,包含,相离太远返回False
  81. maxInterval = maxDistance
  82. status, interval, lineNear, lineFar = self.getLengthwaysDistance(line1, line2, direct1)
  83. if ((status == 1) and (interval > maxInterval)) or (status == -1):
  84. return False, line1
  85. # 4 合并相离不远、相交和包含的线段
  86. point1 = lineNear[0],lineNear[1]
  87. point2 = self.getMaxPoint([lineNear[2], lineNear[3]],[lineFar[0], lineFar[1]],[lineFar[2], lineFar[3]])
  88. retLine = [-1,-1,-1,-1]
  89. if direct1 == 1:
  90. retLine[0] = point1[0]
  91. retLine[2] = point2[0]
  92. retLine[1] = (point1[1] + point2[1])/2
  93. retLine[3] = (point1[1] + point2[1])/2
  94. else:
  95. retLine[1] = point1[1]
  96. retLine[3] = point2[1]
  97. retLine[0] = (point1[0] + point2[0])/2
  98. retLine[2] = (point1[0] + point2[0])/2
  99. return True, retLine
  100. '''
  101. 例如:[1002 ,134,1002 , 43] 调整为[1002,43,1002,134]
  102. '''
  103. def toOriginLine(self, line):
  104. retLine = line
  105. if (line[0] + line[1]) > (line[2]+line[3]):
  106. retLine = [line[2] , line[3], line[0],line[1]]
  107. return retLine
  108. def getMaxPoint(self, *pointList):
  109. # print "getMaxPoint:",pointList
  110. maxPoint = [-1,-1]
  111. for point in pointList:
  112. if (maxPoint[0] + maxPoint[1]) < (point[0] + point[1]):
  113. maxPoint[0] = point[0]
  114. maxPoint[1] = point[1]
  115. return maxPoint
  116. def getMinPoint(self, *pointList):
  117. # print "getMinPoint:",pointList
  118. minPoint = [10000,10000]
  119. for point in pointList:
  120. if (minPoint[0] + minPoint[1]) > (point[0] + point[1]):
  121. minPoint[0] = point[0]
  122. minPoint[1] = point[1]
  123. return minPoint
  124. '''
  125. 找到所有线段中的最小坐标点和最大坐标点
  126. '''
  127. def getLineMMPoint(self, lineList):
  128. minPoint = [10000,10000]
  129. maxPoint = [-1,-1]
  130. for line in lineList:
  131. minPoint = self.getMinPoint(minPoint, (line[0],line[1]), (line[2],line[3]))
  132. maxPoint = self.getMaxPoint(maxPoint, (line[0],line[1]), (line[2],line[3]))
  133. return minPoint,maxPoint
  134. '''
  135. 查看line是水平线段,还是竖直线段,或者其他斜线
  136. :param line1:[x1, y1, x2, y2],线段1
  137. :param line2:[x1, y1, x2, y2],线段2
  138. :param direct:1 代表水平,2代表竖直
  139. :return int:1 代表相离,2 代表相交,3 代表包含, -1 代表识别异常
  140. :return int:相离的距离,-1或者相离实际距离
  141. :return line1: 接近原点的线段
  142. :return line2: 远离原点的线段
  143. '''
  144. def getLengthwaysDistance(self, line1, line2, direct):
  145. status = -1
  146. distance = -1
  147. tallLine = line1
  148. shortLine = line2
  149. lineLen1 = self.caculateLinLen(line1)
  150. lineLen2 = self.caculateLinLen(line2)
  151. if (lineLen1 > lineLen2):
  152. tallLine = line1
  153. shortLine = line2
  154. else:
  155. tallLine = line2
  156. shortLine = line1
  157. if (direct == 1):
  158. if (tallLine[1] < shortLine[1]) and (tallLine[3] < shortLine[1]):
  159. status = 1
  160. distance = shortLine[1] - tallLine[3]
  161. return status, distance, tallLine, shortLine
  162. if (tallLine[1] < shortLine[1]) and (tallLine[3] >= shortLine[1]) and (tallLine[3] < shortLine[3]):
  163. status = 2
  164. distance = -1
  165. return status, distance, tallLine, shortLine
  166. if (tallLine[1] <= shortLine[1]) and (tallLine[3] >= shortLine[3]):
  167. status = 3
  168. distance = -1
  169. return status, distance, tallLine, shortLine
  170. if (tallLine[1] > shortLine[1]) and (tallLine[1] <= shortLine[3]) and (tallLine[3] > shortLine[3]):
  171. status = 2
  172. distance = -1
  173. return status, distance, shortLine, tallLine
  174. if (tallLine[1] > shortLine[3]) and (tallLine[3] > shortLine[3]):
  175. status = 1
  176. distance = tallLine[1] - shortLine[3]
  177. return status, distance, shortLine, tallLine
  178. if (direct == 2):
  179. if (tallLine[0] < shortLine[0]) and (tallLine[2] < shortLine[0]):
  180. status = 1
  181. distance = shortLine[0] - tallLine[2]
  182. return status, distance, tallLine, shortLine
  183. if (tallLine[0] < shortLine[0]) and (tallLine[2] >= shortLine[0]) and (tallLine[2] < shortLine[2]):
  184. status = 2
  185. distance = -1
  186. return status, distance, tallLine, shortLine
  187. if (tallLine[0] <= shortLine[0]) and (tallLine[2] >= shortLine[2]):
  188. status = 3
  189. distance = -1
  190. return status, distance, tallLine, shortLine
  191. if (tallLine[0] > shortLine[0]) and (tallLine[0] <= shortLine[2]) and (tallLine[2] > shortLine[2]):
  192. status = 2
  193. distance = -1
  194. return status, distance, shortLine, tallLine
  195. if (tallLine[0] > shortLine[2]) and (tallLine[2] > shortLine[2]):
  196. status = 1
  197. distance = tallLine[0] - shortLine[2]
  198. return status, distance, shortLine, tallLine
  199. return status, distance, shortLine, tallLine
  200. '''
  201. 查看line是水平线段,还是竖直线段,或者其他斜线
  202. :param line1:[x1, y1, x2, y2],线段1
  203. :param line2:[x1, y1, x2, y2],线段2
  204. :param direct:1 代表水平,2代表竖直
  205. :return int:1 代表水平,2代表竖直,0代表其他斜线
  206. '''
  207. def getParalDistance(self, line1, line2, direct):
  208. if direct == 1:
  209. return abs(line1[1] - line2[1])
  210. if direct == 2:
  211. return abs(line1[0] - line2[0])
  212. '''
  213. 查看line是水平线段,还是竖直线段,或者其他斜线
  214. :param line:[x1, y1, x2, y2],线段
  215. :return bool:1 代表水平,2代表竖直,0代表其他斜线
  216. '''
  217. def lineDirect(self, line):
  218. if (line[0] == line[2]):
  219. return 2
  220. elif (line[1] == line[3]):
  221. return 1
  222. else:
  223. return 0
  224. def caculateLinLen(self, line):
  225. dx = abs(line[0] - line[2])
  226. dy = abs(line[1] - line[3])
  227. # print "caculateLinLen:",dx,dy
  228. lineLen = np.sqrt(np.square(dx) + np.square(dy))
  229. return lineLen