import numpy as np import cv2,time,math def get_ms(time2, time1): return (time2-time1)*1000.0 # 根据两点坐标,求过这两点的直线解析方程: a*x+b*y+c = 0 (a >= 0) def getLinearEquation(p1x, p1y, p2x, p2y): sign = 1 a = p2y - p1y if a < 0: sign = -1 a = sign * a b = sign * (p1x - p2x) c = sign * (p1y * p2x - p1x * p2y) # y=kx+bb k = -a/(b+0.0000000001) bb = -c/(b+0.000000000001) return k, bb # 根据多点坐标拟合直线 def best_fit(X, Y): xbar = sum(X) / len(X) ybar = sum(Y) / len(Y) n = len(X) # or len(Y) numer = sum([xi * yi for xi, yi in zip(X, Y)]) - n * xbar * ybar denum = sum([xi ** 2 for xi in X]) - n * xbar ** 2 k = numer / denum b = ybar - k * xbar # print('best fit line:\ny = {:.2f}x + {:.2f}'.format(k, b)) return k, b # 对于左侧车道线,返回两车道线中心点连线确定的角度,radian2表示弧度 def calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber): radian2 = math.atan2(abs(allLaneContent[leftLaneSerialNumber[-1]][4][1] - allLaneContent[leftLaneSerialNumber[0]][4][1]), abs(allLaneContent[leftLaneSerialNumber[-1]][4][0] - allLaneContent[leftLaneSerialNumber[0]][4][0])) lanesCenterAngle1 = 180 - int(radian2 * 180 / math.pi) lanesCenterAngle2 = int(radian2 * 180 / math.pi) return lanesCenterAngle1, lanesCenterAngle2 # 对于右侧车道线,返回两车道线中心点连线确定的角度,radian2表示弧度 def calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber): radian2 = math.atan2(abs(allLaneContent[rightLaneSerialNumber[-1]][4][1] - allLaneContent[rightLaneSerialNumber[0]][4][1]), abs(allLaneContent[rightLaneSerialNumber[-1]][4][0] - allLaneContent[rightLaneSerialNumber[0]][4][0])) lanesCenterAngle3 = 180 - int(radian2 * 180 / math.pi) lanesCenterAngle4 = int(radian2 * 180 / math.pi) return lanesCenterAngle3, lanesCenterAngle4 # 从所有车道线中确定位于最左侧的车道线簇,并将各车道线对应的序号存储在leftLaneSerialNumber中 def findLeftLanes(allLaneContent, laneXCoordinateMin2MaxSort, leftLaneSerialNumber, pars): for i in range(len(laneXCoordinateMin2MaxSort)): # 求最左侧车道线 if (allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0] > allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0] and allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1] < allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]) or (allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0] < allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0] and allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1] > allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]): # allLaneContent[0][4][0]:中心点x坐标。 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 radian1 = math.atan2(abs(allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1] - allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1]), abs(allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0] - allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0])) lanesCenterAngle1 = 180 - int(radian1 * 180 / math.pi) if len(leftLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMin2MaxSort[i][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i][1]) if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break else: if (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][0] == allLaneContent[leftLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif (allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0] < allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0] and allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1] < allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]) or (allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0] > allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0] and allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1] > allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]): # 这种情况对应左上角和右下角的车道线,计算角度 radian1 = math.atan2(abs(allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1] - allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1]), abs(allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0] - allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0])) lanesCenterAngle1 = int(radian1 * 180 / math.pi) if len(leftLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMin2MaxSort[i][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i][1]) if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break else: if (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or ( allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][0] == allLaneContent[leftLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][0] == allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle1 = 90 if len(leftLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMin2MaxSort[i][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i][1]) if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break else: if (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][0] == allLaneContent[leftLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[laneXCoordinateMin2MaxSort[i][1]][4][1] == allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle1 = 0 if len(leftLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMin2MaxSort[i][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i][1]) if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break else: if (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif (allLaneContent[leftLaneSerialNumber[0]][4][0] < allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] < allLaneContent[leftLaneSerialNumber[-1]][4][1]) or (allLaneContent[leftLaneSerialNumber[0]][4][0] > allLaneContent[leftLaneSerialNumber[-1]][4][0] and allLaneContent[leftLaneSerialNumber[0]][4][1] > allLaneContent[leftLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateLeftLanesAngle(allLaneContent, leftLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][0] == allLaneContent[leftLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break elif allLaneContent[leftLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMin2MaxSort[i + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMin2MaxSort[i + 1][1] not in leftLaneSerialNumber: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[i + 1][1]) else: break return leftLaneSerialNumber # 从所有车道线中确定位于最右侧的车道线簇,并将各车道线对应的序号存储在rightLaneSerialNumber中 def findRightLanes(allLaneContent, laneXCoordinateMax2MinSort, rightLaneSerialNumber, pars): for r in range(len(laneXCoordinateMax2MinSort)): # 求最右侧车道线 if (allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0] > allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0] and allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1] < allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]) or (allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0] < allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0] and allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1] > allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]): # allLaneContent[0][4][0]:中心点x坐标。 车辆的相对位置不同,计算角度方法也不同。 radian1 = math.atan2(abs(allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1] - allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1]), abs(allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0] - allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0])) lanesCenterAngle1 = 180 - int(radian1 * 180 / math.pi) if len(rightLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMax2MinSort[r][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r][1]) if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break else: if (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][0] == allLaneContent[rightLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif (allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0] < allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0] and allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1] < allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]) or (allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0] > allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0] and allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1] > allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]): radian1 = math.atan2(abs(allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1] - allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1]), abs(allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0] - allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0])) lanesCenterAngle1 = int(radian1 * 180 / math.pi) if len(rightLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMax2MinSort[r][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r][1]) if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break else: if (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][0] == allLaneContent[rightLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][0] == allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][0]: lanesCenterAngle1 = 90 if len(rightLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMax2MinSort[r][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r][1]) if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break else: if (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][0] == allLaneContent[rightLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[laneXCoordinateMax2MinSort[r][1]][4][1] == allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]: lanesCenterAngle1 = 0 if len(rightLaneSerialNumber) == 0: # 刚开始判断 if abs(allLaneContent[laneXCoordinateMax2MinSort[r][1]][6] - lanesCenterAngle1) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r][1]) if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break else: if (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[0]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif (allLaneContent[rightLaneSerialNumber[0]][4][0] < allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] < allLaneContent[rightLaneSerialNumber[-1]][4][1]) or (allLaneContent[rightLaneSerialNumber[0]][4][0] > allLaneContent[rightLaneSerialNumber[-1]][4][0] and allLaneContent[rightLaneSerialNumber[0]][4][1] > allLaneContent[rightLaneSerialNumber[-1]][4][1]): # 车辆的相对位置不同,计算角度方法也不同。这种情况对应右上角和左下角的车道线,计算角度 if abs(lanesCenterAngle1 - calculateRightLanesAngle(allLaneContent, rightLaneSerialNumber)[1]) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][0] == allLaneContent[rightLaneSerialNumber[-1]][4][0]: # 两车道线的最小x坐标相同 lanesCenterAngle2 = 90 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break elif allLaneContent[rightLaneSerialNumber[0]][4][1] == allLaneContent[laneXCoordinateMax2MinSort[r + 1][1]][4][1]: # 两车道线的y坐标相同 lanesCenterAngle2 = 0 if abs(lanesCenterAngle1 - lanesCenterAngle2) <= pars['laneAngleCha']: if laneXCoordinateMax2MinSort[r + 1][1] not in rightLaneSerialNumber: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[r + 1][1]) else: break return rightLaneSerialNumber # 返回最左侧车道线簇所确定的直线的k和b值,将其存储在leftLaneKB中 def calculateLeftLane_k_b(allLaneContent, laneXCoordinateMin2MaxSort, leftLaneSerialNumber, leftLaneBox, leftLaneAbovePoint, leftLaneKB, leftLaneCenterX, leftLaneCenterY, pars): leftLaneSerialNumber = findLeftLanes(allLaneContent, laneXCoordinateMin2MaxSort, leftLaneSerialNumber, pars) if len(leftLaneSerialNumber) == 0: leftLaneSerialNumber.append(laneXCoordinateMin2MaxSort[0][1]) # leftLaneSerialNumber中存放的是最左侧的车道线簇中的各车道线的序号 if len(leftLaneSerialNumber) == 1: centerCoordinate = allLaneContent[leftLaneSerialNumber[0]][4] # 最小外接矩形的中心点坐标 box = allLaneContent[leftLaneSerialNumber[0]][5] leftLaneBox.append([box[0][0], box[0][1]]) leftLaneBox.append([box[1][0], box[1][1]]) leftLaneBox.append([box[2][0], box[2][1]]) leftLaneBox.append([box[3][0], box[3][1]]) for i in range(len(leftLaneBox)): if leftLaneBox[i][1] < centerCoordinate[1]: leftLaneAbovePoint.append(leftLaneBox[i]) point1_l = [(leftLaneAbovePoint[0][0] + leftLaneAbovePoint[1][0]) / 2, (leftLaneAbovePoint[0][1] + leftLaneAbovePoint[1][1]) / 2] point2_l = [centerCoordinate[0], centerCoordinate[1]] k_l, b_l = getLinearEquation(point1_l[0], point1_l[1], point2_l[0], point2_l[1]) leftLaneKB.append(k_l) leftLaneKB.append(b_l) else: for i in range(len(leftLaneSerialNumber)): leftLaneCenterX.append(allLaneContent[leftLaneSerialNumber[i]][4][0]) # leftLaneCenterX中存储的是各车道线中心点的x坐标 leftLaneCenterY.append(allLaneContent[leftLaneSerialNumber[i]][4][1]) # leftLaneCenterY中存储的是各车道线中心点的y坐标 k_l, b_l = best_fit(leftLaneCenterX, leftLaneCenterY) leftLaneKB.append(k_l) leftLaneKB.append(b_l) return leftLaneKB # 返回最右侧车道线簇所确定的直线的k和b值,将其存储在rightLaneKB中 def calculateRightLane_k_b(allLaneContent, laneXCoordinateMax2MinSort, rightLaneSerialNumber, rightLaneBox, rightLaneAbovePoint, rightLaneKB, rightLaneCenterX, rightLaneCenterY, pars): rightLaneSerialNumber = findRightLanes(allLaneContent, laneXCoordinateMax2MinSort, rightLaneSerialNumber, pars) if len(rightLaneSerialNumber) == 0: rightLaneSerialNumber.append(laneXCoordinateMax2MinSort[0][1]) # rightLaneSerialNumber中存放的是最右侧的车道线簇中的各车道线的序号 if len(rightLaneSerialNumber) == 1: centerCoordinate = allLaneContent[rightLaneSerialNumber[0]][4] # 最小外接矩形的中心点坐标 box = allLaneContent[rightLaneSerialNumber[0]][5] rightLaneBox.append([box[0][0], box[0][1]]) rightLaneBox.append([box[1][0], box[1][1]]) rightLaneBox.append([box[2][0], box[2][1]]) rightLaneBox.append([box[3][0], box[3][1]]) for i in range(len(rightLaneBox)): if rightLaneBox[i][1] < centerCoordinate[1]: rightLaneAbovePoint.append(rightLaneBox[i]) point1_r = [(rightLaneAbovePoint[0][0] + rightLaneAbovePoint[1][0]) / 2, (rightLaneAbovePoint[0][1] + rightLaneAbovePoint[1][1]) / 2] point2_r = [centerCoordinate[0], centerCoordinate[1]] k_r, b_r = getLinearEquation(point1_r[0], point1_r[1], point2_r[0], point2_r[1]) rightLaneKB.append(k_r) rightLaneKB.append(b_r) else: for i in range(len(rightLaneSerialNumber)): rightLaneCenterX.append(allLaneContent[rightLaneSerialNumber[i]][4][0]) # rightLaneCenterX中存储的是各车道线中心点的x坐标 rightLaneCenterY.append(allLaneContent[rightLaneSerialNumber[i]][4][1]) # rightLaneCenterY中存储的是各车道线中心点的y坐标 k_r, b_r = best_fit(rightLaneCenterX, rightLaneCenterY) rightLaneKB.append(k_r) rightLaneKB.append(b_r) return rightLaneKB def mixNoParking_road_postprocess(dets, mask, pars): """ 对于字典traffic_dict中的各个键,说明如下: speedRoadArea:speedRoad的最小外接矩形的面积 vehicleCoordinate:是一个列表,用于存储被检测出的vehicle的坐标(vehicle检测模型) roundness:圆度 ,lane的长与宽的比率,作为判定是否为车道线的标准之一 'cls':类别号 vehicleArea:vehicle的最小外接矩形的面积 laneLineArea:车道线的最小外接矩形的面积 laneAngleCha:车道线的角度差值阈值 contoursNum:counters中的顶点个数 ZoomFactor:图像在H和W方向上的缩放因子,其值小于1 最终输出格式:[[cls, x0, y0, x1, y1, 车辆得分, 违章停车得分, 违章类别], ...] 违章类别:0表示正常车辆,1表示违章车辆 """ det_cors = [] for bb in dets: det_cors.append((int(bb[1]), int(bb[2]))) det_cors.append((int(bb[3]), int(bb[4]))) pars['vehicleCoordinate'] = det_cors H, W = mask.shape[0:2] scaleH = pars['modelSize'][1] / H # 自适应调整缩放比例 scaleW = pars['modelSize'][0] / W pars['ZoomFactor'] = {'x': scaleH, 'y': scaleW} new_hw = [int(H * scaleH), int(W * scaleW)] mask = cv2.resize(mask, (new_hw[1], new_hw[0])) if len(mask.shape) == 3: mask = mask[:, :, 0] t3 = time.time() vehicleContours = [] # 存储一副图像中vehicles的contours image_speedRoad = mask.copy() image_vehicle = mask.copy() lane_line = mask.copy() image_speedRoad[image_speedRoad == 2] = 0 # 将vehicle过滤掉,只包含背景和speedRoad image_vehicle[image_vehicle == 1] = 0 # 将speedRoad过滤掉,只包含背景和vehicle lane_line[lane_line < 3] = 0 image_speedRoad = cv2.cvtColor(np.uint8(image_speedRoad), cv2.COLOR_RGB2BGR) # 道路 image_vehicle = cv2.cvtColor(np.uint8(image_vehicle), cv2.COLOR_RGB2BGR) # 车辆 lane_line = cv2.cvtColor(np.uint8(lane_line), cv2.COLOR_RGB2BGR) # t4 = time.time() img1 = cv2.cvtColor(image_speedRoad, cv2.COLOR_BGR2GRAY) contours, hierarchy = cv2.findContours(img1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) t5 = time.time() # 创建列表 singleSpeedRoadContent, allSpeedRoadContent, complianceVehicle, NonComplianceVehicle, singleLaneContent, allLaneContent, laneMinXCoordinate, laneMaxXCoordinate, leftLaneSerialNumber, leftLaneBox, leftLaneAbovePoint, leftLaneKB, leftLaneCenterX, leftLaneCenterY, rightLaneSerialNumber, rightLaneBox, rightLaneAbovePoint, rightLaneKB, rightLaneCenterX, rightLaneCenterY = ([] for t in range(20)) """ 列表说明如下: singleSpeedRoadContent = [] # 过渡使用 allSpeedRoadContent = [] # 存放speedRoad坐标(Xmin,Xmax,Ymin,Ymax)、speedRoadAngle和speedRoad的宽高 complianceVehicle = [] # 将符合标准的vehicle信息存储在complianceVehicle中 NonComplianceVehicle = [] # 将不符合标准的vehicle信息存储在NonComplianceVehicle中 singleLaneContent = [] # 存储单个车道线的相关信息 allLaneContent = [] # 将singleLaneContent中的车道线存储在allLaneContent中 laneMinXCoordinate = [] # 存储车道线的最小x坐标 laneMaxXCoordinate = [] # 存储车道线的最大x坐标 leftLaneSerialNumber = [] # 左侧车道线簇中的车道线序号 leftLaneBox = [] # 当左侧车道线簇中只有一个车道线时,该车道线的最小外接矩形对应的box leftLaneAbovePoint = [] # 当左侧车道线簇中只有一个车道线时,该车道线的最小外接矩形最上方的两个顶点坐标 leftLaneKB = [] # 存储最左侧车道线簇所确定的直线的k和b值 leftLaneCenterX = [] # 左侧车道线簇中各车道线中心点的x坐标 leftLaneCenterY = [] # 左侧车道线簇中各车道线中心点的y坐标 rightLaneSerialNumber = [] # 右侧车道线簇中的车道线序号 rightLaneBox = [] # 当右侧车道线簇中只有一个车道线时,该车道线的最小外接矩形对应的box rightLaneAbovePoint = [] # 当右侧车道线簇中只有一个车道线时,该车道线的最小外接矩形最上方的两个顶点坐标 rightLaneKB = [] # 存储最左侧车道线簇所确定的直线的k和b值 rightLaneCenterX = [] # 右侧车道线簇中各车道线中心点的x坐标 rightLaneCenterY = [] # 右侧车道线簇中各车道线中心点的y坐标 """ """ 将speedRoad最小外接矩形的四个顶点(Xmin,Xmax,Ymin,Ymax)、其最小外接矩形与水平方向的夹角、其最小外接矩形的宽高存储在singleSpeedRoadContent中 """ for cnt in contours: # 道路 if len(cnt) >= 6: rect = cv2.minAreaRect(cnt) if rect[1][0] * rect[1][1] > pars['speedRoadArea']: # 过滤掉面积小于阈值的speedRoad box = cv2.boxPoints(rect).astype(np.int32) speedRoadXmin = min(box[0][0], box[1][0], box[2][0], box[3][0]) speedRoadXmax = max(box[0][0], box[1][0], box[2][0], box[3][0]) speedRoadYmin = min(box[0][1], box[1][1], box[2][1], box[3][1]) speedRoadYmax = max(box[0][1], box[1][1], box[2][1], box[3][1]) singleSpeedRoadContent.append(speedRoadXmin) singleSpeedRoadContent.append(speedRoadXmax) singleSpeedRoadContent.append(speedRoadYmin) singleSpeedRoadContent.append(speedRoadYmax) if rect[1][0] <= rect[1][1]: if rect[2] >= 0 and rect[2] < 90: speedRoadAngle = rect[2] + 90 elif rect[2] == 90: speedRoadAngle = 0 else: if rect[2] >= 0 and rect[2] <= 90: speedRoadAngle = rect[2] singleSpeedRoadContent.append(speedRoadAngle) singleSpeedRoadContent.append(rect[1]) allSpeedRoadContent.append(singleSpeedRoadContent) singleSpeedRoadContent = [] img3 = cv2.cvtColor(lane_line, cv2.COLOR_BGR2GRAY) contours, hierarchy = cv2.findContours(img3, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) """ 将车道线最小外接矩形四个顶点(Xmin,Xmax,Ymin,Ymax)、车道线最小外接矩形的中心点坐标,车道线矩形框与水平方向的夹角,存储在singleLaneContent中 """ for cnt in contours: # 车道线 if len(cnt) >= 6: if rect[1][0] * rect[1][1] > pars['laneLineArea'] and min(rect[1]) / max(rect[1]) <= pars['roundness']: rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect).astype(np.int32) box = np.array(box) laneXmin, laneXmax = np.min( box[:,0] ),np.max( box[:,0] ) laneYmin, laneYmax = np.min( box[:,1] ),np.max( box[:,1] ) #laneXmin = min(box[0][0], box[1][0], box[2][0], box[3][0]) #laneXmax = max(box[0][0], box[1][0], box[2][0], box[3][0]) #laneYmin = min(box[0][1], box[1][1], box[2][1], box[3][1]) #laneYmax = max(box[0][1], box[1][1], box[2][1], box[3][1]) singleLaneContent.append(laneXmin) # 将车道线矩形框四个顶点的Xmin,Xmax,Ymin,Ymax存储在singleLaneContent中 singleLaneContent.append(laneXmax) singleLaneContent.append(laneYmin) singleLaneContent.append(laneYmax) if rect[1][0] <= rect[1][1]: if rect[2] >= 0 and rect[2] < 90: laneLineAngle = rect[2] + 90 elif rect[2] == 90: laneLineAngle = 0 else: if rect[2] >= 0 and rect[2] <= 90: laneLineAngle = rect[2] singleLaneContent.append(rect[0]) # 将车道线的中心点坐标存储在singleLaneContent中 singleLaneContent.append(box) # 将车道线的最小外接矩形的顶点坐标存储在singleLaneContent中 singleLaneContent.append(laneLineAngle) # 将车道线矩形框与水平方向的夹角存储在singleLaneContent中 allLaneContent.append(singleLaneContent) # 将车道线存储在allLaneContent中 singleLaneContent = [] if len(allSpeedRoadContent) != 0 and len(allLaneContent) >= 2: # 图像中存在speedRoad且车道线的个数大于等于2 for i in range(len(allLaneContent)): laneMinXCoordinate.append([allLaneContent[i][0], i]) # 存储车道线的最小x坐标 laneMaxXCoordinate.append([allLaneContent[i][1], i]) # 存储车道线的最大x坐标 laneXCoordinateMin2MaxSort = sorted(laneMinXCoordinate, key=(lambda x: x[0])) # laneXCoordinateMin2MaxSort中存储的是各车道线的x的最小值从小到大排列,后面跟车道线的序号 laneXCoordinateMax2MinSort = sorted(laneMaxXCoordinate, key=(lambda x: x[0]), reverse=True) # laneXCoordinateMax2MinSort中存储的是各车道线的x的最大值从大到小排列,后面跟车道线的序号 # 计算最左侧车道线簇所确定的直线的k和b值,将其存储在leftLaneKB中 leftLaneKB = calculateLeftLane_k_b(allLaneContent, laneXCoordinateMin2MaxSort, leftLaneSerialNumber, leftLaneBox, leftLaneAbovePoint, leftLaneKB, leftLaneCenterX, leftLaneCenterY, pars) # 计算最右侧车道线簇所确定的直线的k和b值,将其存储在rightLaneKB中 rightLaneKB = calculateRightLane_k_b(allLaneContent, laneXCoordinateMax2MinSort, rightLaneSerialNumber, rightLaneBox, rightLaneAbovePoint, rightLaneKB, rightLaneCenterX, rightLaneCenterY, pars) count = 0 for i in range(0, len(pars['vehicleCoordinate']), 2): vehicleAreaList = [] mask = np.zeros(image_vehicle.shape[:2], dtype="uint8") x0 = int(pars['vehicleCoordinate'][i][0] * pars['ZoomFactor']['x']) y0 = int(pars['vehicleCoordinate'][i][1] * pars['ZoomFactor']['y']) x1 = int(pars['vehicleCoordinate'][i + 1][0] * pars['ZoomFactor']['x']) y1 = int(pars['vehicleCoordinate'][i + 1][1] * pars['ZoomFactor']['y']) cv2.rectangle(mask, (x0, y0), (x1, y1), 255, -1, lineType=cv2.LINE_AA) image_vehicle_masked = cv2.bitwise_and(image_vehicle, image_vehicle, mask=mask) img2 = cv2.cvtColor(image_vehicle_masked, cv2.COLOR_BGR2GRAY) contours2, hierarchy2 = cv2.findContours(img2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) """ 将符合标准的vehicle信息存储在complianceVehicle中,将不符合标准的vehicle信息存储在NonComplianceVehicle中 """ ##主要做面积的过滤。 if len(contours2) != 0: if len(contours2) > 1: # 这里我通过比较同一检测框内各个contours对应的最小外接矩形的面积,来剔除那些存在干扰的contours,最终只保留一个contours for j in range(len(contours2)): contours_j = contours2[j] rect = cv2.minAreaRect(contours_j) vehicleAreaList.append(rect[1][0] * rect[1][1]) if max(vehicleAreaList) >= pars['vehicleArea']: maxAreaIndex = vehicleAreaList.index(max(vehicleAreaList)) maxAreacontours = contours2[maxAreaIndex] if len(maxAreacontours) >= 6: vehicleContours.append(maxAreacontours) complianceVehicle.append(dets[count]) else: dets[int(i / 2)].append(0) dets[int(i / 2)].append(0) NonComplianceVehicle.append(dets[int(i / 2)]) else: dets[int(i / 2)].append(0) dets[int(i / 2)].append(0) NonComplianceVehicle.append(dets[int(i / 2)]) elif len(contours2) == 1: contours_j = contours2[0] rect = cv2.minAreaRect(contours_j) if rect[1][0] * rect[1][1] >= pars['vehicleArea']: if len(contours_j) >= 6: vehicleContours.append(contours_j) complianceVehicle.append(dets[count]) else: dets[int(i / 2)].append(0) dets[int(i / 2)].append(0) NonComplianceVehicle.append(dets[int(i / 2)]) else: dets[int(i / 2)].append(0) dets[int(i / 2)].append(0) NonComplianceVehicle.append(dets[int(i / 2)]) else: dets[int(i/2)].append(0) dets[int(i/2)].append(0) NonComplianceVehicle.append(dets[int(i/2)]) count += 1 dets = complianceVehicle """ 对vehicle是否在speedRoad上进行判断,并计算违章得分 """ if len(vehicleContours) != 0: for i in range(len(vehicleContours)): rect = cv2.minAreaRect(vehicleContours[i]) if len(allSpeedRoadContent) != 0: for j in range(len(allSpeedRoadContent)): # 判断车辆矩形框的中心点坐标是否在道路矩形框Xmin,Xmax,Ymin和Ymax的范围内; if (rect[0][0] > allSpeedRoadContent[j][0] and rect[0][0] < allSpeedRoadContent[j][1]) and (rect[0][1] > allSpeedRoadContent[j][2] and rect[0][1] < allSpeedRoadContent[j][3]): # 将Box2D结构作为输入并返回4个角点。 box = cv2.boxPoints(rect).astype(np.int32) # 比较车辆矩形框四个顶点的坐标是否都在道路矩形框Xmin,Xmax,Ymin和Ymax的范围内,若都在,则说明该车辆在这条道路上。 if (box[0][0] >= allSpeedRoadContent[j][0] and box[0][0] <= allSpeedRoadContent[j][1] and box[0][1] >= allSpeedRoadContent[j][2] and box[0][1] <= allSpeedRoadContent[j][3]) and (box[1][0] >= allSpeedRoadContent[j][0] and box[1][0] <= allSpeedRoadContent[j][1] and box[1][1] >= allSpeedRoadContent[j][2] and box[1][1] <= allSpeedRoadContent[j][3]) and (box[2][0] >= allSpeedRoadContent[j][0] and box[2][0] <= allSpeedRoadContent[j][1] and box[2][1] >= allSpeedRoadContent[j][2] and box[2][1] <= allSpeedRoadContent[j][3]) and (box[3][0] >= allSpeedRoadContent[j][0] and box[3][0] <= allSpeedRoadContent[j][1] and box[3][1] >= allSpeedRoadContent[j][2] and box[3][1] <= allSpeedRoadContent[j][3]): dets[i].append(0) # 给违章得分占位 dets[i].append(0) # 给违章类别占位 # 当车道线个数至少有两条时,才计算违章得分 if len(allLaneContent) >= 2: if rect[0][1] < leftLaneKB[0] * rect[0][0] + leftLaneKB[1]: distanceCenterToLine = abs(leftLaneKB[0] * rect[0][0] - rect[0][1] + leftLaneKB[1]) / math.sqrt(leftLaneKB[0] * leftLaneKB[0] + 1) if distanceCenterToLine >= min(rect[1]) / 2: dets[i][6] = 1 dets[i][7] = 1 else: score4 = distanceCenterToLine / (min(rect[1]) / 2) dets[i][6] = score4 dets[i][7] = 1 elif rect[0][1] < rightLaneKB[0] * rect[0][0] + rightLaneKB[1]: distanceCenterToLine = abs(rightLaneKB[0] * rect[0][0] - rect[0][1] + rightLaneKB[1]) / math.sqrt(rightLaneKB[0] * rightLaneKB[0] + 1) if distanceCenterToLine >= min(rect[1]) / 2: dets[i][6] = 1 dets[i][7] = 1 else: score4 = distanceCenterToLine / (min(rect[1]) / 2) dets[i][6] = score4 dets[i][7] = 1 break # 如果分割图像中不存在speedRoad,则无法进行违章判定,将所有车辆的违章类别设为0,即没有违章 if len(dets[i]) < 8: dets[i].append(0) # 违章得分为0 dets[i].append(0) # 0表示没有违章 targetList = dets for i in range(len(NonComplianceVehicle)): targetList.append(NonComplianceVehicle[i]) # 将所有车辆的信息合并到一起 # 目标对象, [[cls, x0, y0, x1, y1, score, 违章得分, 违章类别], ...] else: targetList = NonComplianceVehicle t6 = time.time() time_infos = 'postTime:%.2f (分割时间:%.2f, findContours:%.2f ruleJudge:%.2f)' % ( get_ms(t6, t3), get_ms(t4, t3), get_ms(t5, t4), get_ms(t6, t5)) targetList = [ [ b[7] ,*b[1:5],b[6] if b[6]>0 else b[5]] for b in targetList ] #最终输出格式:[[cls, x0, y0, x1, y1, 车辆得分, 违章停车得分, 违章类别], ...] return targetList, time_infos