# 设定开关，将最小外接矩形中心点间的距离作为vehicle之间的距离
import numpy as np
import math, cv2, time
from copy import deepcopy

def xyxy_coordinate(boundbxs,contour):
    '''
    输入：两个对角坐标xyxy
    输出：四个点位置
    '''
    x1 = boundbxs[0]
    y1 = boundbxs[1]
    x2 = boundbxs[2]
    y2 = boundbxs[3]

    for x in (x1,x2):
        for y in (y1,y2):
            flag = cv2.pointPolygonTest(contour, (int(x), int(y)),
                                        False)  # 若为False，会找点是否在内，外，或轮廓上(相应返回+1, -1, 0)。
            if flag == 1:
                return 1

    return flag

def get_ms(time2, time1):
    return (time2 - time1) * 1000.0


def two_points_distance(x1, y1, x2, y2):
    distance = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
    return distance


# 保存正常vehicle和非正常vehicle的信息（当contours顶点数小于6时，无法拟合最小外接矩形，定义为非正常vehicle）
def saveVehicle1(traffic_dict, contours, normVehicleBD, normVehicle, count, i, unnormVehicle, normVehicleCOOR):
    if len(contours) >= 6:
        normVehicleBD.append(contours)
        normVehicle.append(traffic_dict['det'][count])
        rect = cv2.minAreaRect(contours)
        normVehicleCOOR.append(rect[0])
    else:
        traffic_dict['det'][int(i / 2)] = traffic_dict['det'][int(i / 2)] + [0, 0.3, 999, -1, 3]
        unnormVehicle.append(traffic_dict['det'][int(i / 2)])
    return normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR


# saveVehicle2和saveVehicle1有区别
def saveVehicle2(traffic_dict, contours, normVehicleBD, normVehicle, count, i, unnormVehicle, normVehicleCOOR, centerCOOR):
    if len(contours) >= 6:
        normVehicleBD.append(contours)
        normVehicle.append(traffic_dict['det'][count])
        normVehicleCOOR.append(centerCOOR)
    else:
        traffic_dict['det'][int(i / 2)] = traffic_dict['det'][int(i / 2)] + [0, 0.3, 999, -1, 3]
        unnormVehicle.append(traffic_dict['det'][int(i / 2)])
    return normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR


# 对于不在道路上的vehicle，将输出信息补全
def supplementInformation(traffic_dict, i, roundness, y_min, y_max, imgVehicle, rect):
    score = -1
    traffic_dict['det'][i] = traffic_dict['det'][i] + [0, roundness, 999, [-1, -1, -1], 666]
    if y_min > 0 and y_max < imgVehicle.shape[0] and roundness > traffic_dict['roundness']:  # 过滤掉上下方被speedRoad的边界截断的vehicle
        score = (min(rect[1]) - max(rect[1]) * traffic_dict['roundness']) / (max(rect[1]) * (1 - traffic_dict['roundness']))
    return score


# 判断交通事故类型
def judgeAccidentType(traffic_dict, b):
    if max(traffic_dict['det'][b][9]) == traffic_dict['det'][b][9][0] and traffic_dict['det'][b][9][0] != -1:
        return 0
    elif max(traffic_dict['det'][b][9]) == traffic_dict['det'][b][9][1] and traffic_dict['det'][b][9][1] != -1:
        return 1
    elif max(traffic_dict['det'][b][9]) == traffic_dict['det'][b][9][2] and traffic_dict['det'][b][9][2] != -1:
        return 2
    else:
        return 3


# 计算距离得分
def distanceScore(vehicleWH, index1, index2, smallestDistance, traffic_dict):
    d1 = (min(vehicleWH[index1]) + min(vehicleWH[index2])) / 2
    d2 = min(min(vehicleWH[index1]), min(vehicleWH[index2])) + max(min(vehicleWH[index1]), min(vehicleWH[index2])) / 2
    if smallestDistance == d1:
        score1 = 1
        traffic_dict['det'][index2][9][2] = score1
        traffic_dict['det'][index2][10] = judgeAccidentType(traffic_dict, index2)
    elif smallestDistance < d2:
        score1 = 1 - (smallestDistance - d1) / (d2 - d1)
        if 0 < score1 < 1:
            traffic_dict['det'][index2][9][2] = score1
            traffic_dict['det'][index2][10] = judgeAccidentType(traffic_dict, index2)
        else:
            traffic_dict['det'][index2][10] = judgeAccidentType(traffic_dict, index2)
    else:
        traffic_dict['det'][index2][10] = judgeAccidentType(traffic_dict, index2)
    return traffic_dict['det']


# 计算两个contours之间的最短距离
def array_distance(arr1, arr2):
    '''
    计算两个数组中，每任意两个点之间L2距离
    arr1和arr2都必须是numpy数组
    且维度分别是mx2，nx2
    输出数组维度为mxn
    '''
    m, _ = arr1.shape
    n, _ = arr2.shape
    arr1_power = np.power(arr1, 2)
    arr1_power_sum = arr1_power[:, 0] + arr1_power[:, 1]   # 第1区域，x与y的平方和
    arr1_power_sum = np.tile(arr1_power_sum, (n, 1))       # 将arr1_power_sum沿着y轴复制n倍，沿着x轴复制1倍，这里用于与arr2进行计算。 n x m 维度
    arr1_power_sum = arr1_power_sum.T                      # 将arr1_power_sum进行转置
    arr2_power = np.power(arr2, 2)
    arr2_power_sum = arr2_power[:, 0] + arr2_power[:, 1]       # 第2区域，x与y的平方和
    arr2_power_sum = np.tile(arr2_power_sum, (m, 1))           # 将arr1_power_sum沿着y轴复制m倍，沿着x轴复制1倍，这里用于与arr1进行计算。   m x n 维度
    dis = arr1_power_sum + arr2_power_sum - (2 * np.dot(arr1, arr2.T))   # np.dot(arr1, arr2.T)矩阵相乘，得到xy的值。
    dis = np.sqrt(dis)
    return dis


# 存储所有道路的信息
def storageRoad(contours, allRoadContent, traffic_dict):
    speedRoadAngle = 0
    for cnt in contours:  # 道路
        rect = cv2.minAreaRect(cnt)
        if rect[1][0] * rect[1][1] > traffic_dict['RoadArea']:  # 过滤掉面积小于阈值的speedRoad
            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]
            allRoadContent.append([cnt, speedRoadAngle, rect[1]])
    return allRoadContent


# 存储所有vehicle的信息，方法1
def storageVehicle1(traffic_dict, normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR, imgVehicle):
    #输入：
    #    
    #输出：traffic_dict['det'], normVehicleBD, unnormVehicle, normVehicleCOOR
    #    traffic_dict['det']：resize缩小之后的坐标，类别，得分.[cls,x0,y0,x1,y1,score]
    
    #    normVehicleBD      : 正常车辆的contours。（正常车辆指的是countrous定点数>=6）
    #    unnormVehicle      : resize缩小之后的异常车辆坐标，类别，得分.[cls,x0,y0,x1,y1,score]
    count = 0
    for i in range(0, len(traffic_dict['vehicleCOOR']), 2):
        mask = np.zeros(imgVehicle.shape[:2], dtype="uint8")
        x0 = int(traffic_dict['vehicleCOOR'][i][0] * traffic_dict['ZoomFactor']['y'])
        y0 = int(traffic_dict['vehicleCOOR'][i][1] * traffic_dict['ZoomFactor']['x'])
        x1 = int(traffic_dict['vehicleCOOR'][i + 1][0] * traffic_dict['ZoomFactor']['y'])
        y1 = int(traffic_dict['vehicleCOOR'][i + 1][1] * traffic_dict['ZoomFactor']['x'])
        cv2.rectangle(mask, (x0, y0), (x1, y1), 255, -1, lineType=cv2.LINE_AA)
        imgVehicle_masked = cv2.bitwise_and(imgVehicle, imgVehicle, mask=mask)
        img2 = cv2.cvtColor(imgVehicle_masked, cv2.COLOR_BGR2GRAY)
        contours2, hierarchy2 = cv2.findContours(img2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        if len(contours2) != 0:
            if len(contours2) > 1:  # 这里我通过比较同一检测框内各个contours对应的最小外接矩形的面积，来剔除那些存在干扰的contours，最终只保留一个contours
                vehicleArea = []  # 存储vehicle的最小外接矩形的面积
                for j in range(len(contours2)):
                    rect = cv2.minAreaRect(contours2[j])
                    vehicleArea.append(rect[1][0] * rect[1][1])
                maxAreaIndex = vehicleArea.index(max(vehicleArea))
                maxAreaContours = contours2[maxAreaIndex]
                normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR = saveVehicle1(traffic_dict,maxAreaContours,normVehicleBD,normVehicle,count,i,unnormVehicle, normVehicleCOOR)
            elif len(contours2) == 1:
                normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR = saveVehicle1(traffic_dict,contours2[0],normVehicleBD,normVehicle,count,i,unnormVehicle, normVehicleCOOR)
        else:
            traffic_dict['det'][int(i / 2)] = traffic_dict['det'][int(i / 2)] + [0, 0.3, 999, -1, 3]
            unnormVehicle.append(traffic_dict['det'][int(i / 2)])
        count += 1
    traffic_dict['det'] = normVehicle
    return traffic_dict['det'], normVehicleBD, unnormVehicle, normVehicleCOOR


# 存储所有vehicle的信息，方法2
def storageVehicle2(traffic_dict, normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR, imgVehicle):
    img = cv2.cvtColor(imgVehicle, cv2.COLOR_BGR2GRAY)
    count = 0
    for i in range(0, len(traffic_dict['vehicleCOOR']), 2):
        row1 = int(traffic_dict['vehicleCOOR'][i][1] * traffic_dict['ZoomFactor']['x'])
        row2 = int(traffic_dict['vehicleCOOR'][i + 1][1] * traffic_dict['ZoomFactor']['x'])
        col1 = int(traffic_dict['vehicleCOOR'][i][0] * traffic_dict['ZoomFactor']['y'])
        col2 = int(traffic_dict['vehicleCOOR'][i + 1][0] * traffic_dict['ZoomFactor']['y'])
      
        if row1 >= 2:
            row1 = row1 - 2
        if row2 <= (traffic_dict['modelSize'][1] - 2):
            row2 = row2 + 2
        if col1 >= 2:
            col1 = col1 - 2
        if col2 <= (traffic_dict['modelSize'][0] - 2):
            col2 = col2 + 2
        centerCOOR = (int((col1 + col2) / 2), int((row1 + row2) / 2))
        img1 = img[row1:row2, col1:col2]
        up = np.zeros((20, (col2 - col1)), dtype='uint8')
        left = np.zeros(((40 + row2 - row1), 20), dtype='uint8')

        img1 = np.concatenate((up, img1), axis=0)
        img1 = np.concatenate((img1, up), axis=0)

        img1 = np.concatenate((left, img1), axis=1)
        img2 = np.concatenate((img1, left), axis=1)
        contours2, hierarchy = cv2.findContours(img2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        if len(contours2) != 0:
            if len(contours2) > 1:
                vehicleArea = []  # 存储vehicle的最小外接矩形的面积
                for j in range(len(contours2)):
                    rect = cv2.minAreaRect(contours2[j])
                    vehicleArea.append(rect[1][0] * rect[1][1])
                maxAreaIndex = vehicleArea.index(max(vehicleArea))
                maxAreaContours = contours2[maxAreaIndex]
                normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR = saveVehicle2(traffic_dict,maxAreaContours,normVehicleBD,normVehicle,count,i,unnormVehicle,normVehicleCOOR,centerCOOR)
            elif len(contours2) == 1:
                normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR = saveVehicle2(traffic_dict,contours2[0],normVehicleBD,normVehicle,count,i,unnormVehicle,normVehicleCOOR,centerCOOR)
        else:
            traffic_dict['det'][int(i / 2)] = traffic_dict['det'][int(i / 2)] + [0, 0.3, 999, -1, 3]
            unnormVehicle.append(traffic_dict['det'][int(i / 2)])
        count += 1
    traffic_dict['det'] = normVehicle
    return traffic_dict['det'], normVehicleBD, unnormVehicle, normVehicleCOOR


# 计算角度和长宽比得分
def angleRoundness(normVehicleBD, vehicleBox, vehicleWH, allRoadContent, traffic_dict, normVehicleCOOR, imgVehicle):
    ##输出：vehicleBox, vehicleWH, traffic_dict['det']
    #       vehicleBox--正常车辆通过contours得出的box,[ (x0,y0),(x1,y1),(x2,y2),(x3,y3)]
    #       vehicleWH--正常车辆通过contours得出的box,[ (w,h)]
    #       traffic_dict['det']--[[cls, x0, y0, x1, y1, score, 角度, 长宽比, 最小距离, max([角度得分, 长宽比得分, 最小距离得分]), 交通事故类别], ...]
    for i in range(len(normVehicleBD)):
        ellipse = cv2.fitEllipse(normVehicleBD[i])
        vehicleAngle = 0
        if ellipse[2] >= 0 and ellipse[2] < 90:
            vehicleAngle = 90 + ellipse[2]
        elif ellipse[2] >= 90 and ellipse[2] < 180:
            vehicleAngle = ellipse[2] - 90
        elif ellipse[2] == 180:
            vehicleAngle = 90
        rect = cv2.minAreaRect(normVehicleBD[i])
        box = cv2.boxPoints(rect).astype(np.int32)
        center = normVehicleCOOR[i]
        vehicleBox.append(box)
        vehicleWH.append(rect[1])
        roundness = min(rect[1]) / max(rect[1])
        y_min = np.min(box[:, 1])
        y_max = np.max(box[:, 1])
        if len(allRoadContent) != 0:
            for j in range(len(allRoadContent)):
                flag = cv2.pointPolygonTest(allRoadContent[j][0], center, False)
                if flag >= 0:
                    roadVehicleAngle = abs(vehicleAngle - allRoadContent[j][1])
                    traffic_dict['det'][i] = traffic_dict['det'][i] + [roadVehicleAngle, roundness, 999, [-1, -1, -1], 666]
                    if y_min > 0 and y_max < imgVehicle.shape[0]:  # 过滤掉上下方被speedRoad的边界截断的vehicle
                        if roadVehicleAngle >= traffic_dict['roadVehicleAngle']:  # 当道路同水平方向的夹角与车辆同水平方向的夹角的差值在15°和75°之间时，需要将车辆框出来
                            if roadVehicleAngle > 90:
                                score1 = float((180 - roadVehicleAngle) / 90)
                            else:
                                score1 = float(roadVehicleAngle / 90)
                            traffic_dict['det'][i][9][0] = score1
                        if roundness > traffic_dict['roundness']:
                            score2 = (min(rect[1]) - max(rect[1]) * traffic_dict['roundness']) / (max(rect[1]) * (1 - traffic_dict['roundness']))
                            traffic_dict['det'][i][9][1] = score2
                    break
                else:
                    j += 1
            if len(traffic_dict['det'][i]) == 6:
                traffic_dict['det'][i][9][1] = supplementInformation(traffic_dict, i, roundness, y_min, y_max, imgVehicle, rect)
        else:
            traffic_dict['det'][i][9][1] = supplementInformation(traffic_dict, i, roundness, y_min, y_max, imgVehicle, rect)
        i += 1
    return vehicleBox, vehicleWH, traffic_dict['det']


# 对于某一vehicle，以该vehicle的最小外接矩形的中心点为圆心O1，划定半径范围，求O1与半径范围内的其他vehicle的中心点之间的距离
def vehicleDistance1(normVehicleCOOR, normVehicleBD, traffic_dict, vehicleWH):
    if len(normVehicleCOOR) > 1:
        for b in range(len(normVehicleCOOR)):
            contoursMinDistance = []  # 存储contours之间的最短距离
            tmp = normVehicleCOOR[b]
            normVehicleCOOR[b] = normVehicleCOOR[0]
            normVehicleCOOR[0] = tmp
            targetContours = []  # 存储目标vehicle和中心点同目标车辆中心点之间的距离小于traffic_dict['radius']的vehicle的box
            for c in range(1, len(normVehicleCOOR)):
                if two_points_distance(normVehicleCOOR[0][0], normVehicleCOOR[0][1], normVehicleCOOR[c][0], normVehicleCOOR[c][1]) <= traffic_dict['radius']:
                    if normVehicleBD[b] not in targetContours:
                        targetContours.append(normVehicleBD[b])
                    if c == b:
                        targetContours.append(normVehicleBD[0])
                    else:
                        targetContours.append(normVehicleBD[c])
            if len(targetContours) != 0:
                goalVehicleContour = np.squeeze(targetContours[0], 1)
                for d in range(1, len(targetContours)):
                    elseVehicleContour = np.squeeze(targetContours[d], 1)
                    dist_arr = array_distance(goalVehicleContour, elseVehicleContour)
                    min_dist = dist_arr[dist_arr > 0].min()
                    contoursMinDistance.append(min_dist)
                traffic_dict['det'][b][8] = min(contoursMinDistance)
                if traffic_dict['det'][b][8] < min(vehicleWH[b]) * traffic_dict['vehicleFactor']:
                    score1 = 1 - traffic_dict['det'][b][8] / (min(vehicleWH[b]) * traffic_dict['vehicleFactor'])
                    traffic_dict['det'][b][9][2] = score1
                traffic_dict['det'][b][10] = judgeAccidentType(traffic_dict, b)
            else:
                traffic_dict['det'][b][8] = 999
                traffic_dict['det'][b][10] = judgeAccidentType(traffic_dict, b)
            tmp = normVehicleCOOR[b]
            normVehicleCOOR[b] = normVehicleCOOR[0]
            normVehicleCOOR[0] = tmp
    else:  # 路上只有一辆车
        if max(traffic_dict['det'][0][9]) == traffic_dict['det'][0][9][0] and traffic_dict['det'][0][9][0] != -1:
            traffic_dict['det'][0][10] = 0
        elif max(traffic_dict['det'][0][9]) == traffic_dict['det'][0][9][1] and traffic_dict['det'][0][9][1] != -1:
            traffic_dict['det'][0][10] = 1
        else:
            traffic_dict['det'][0][10] = 3
    return traffic_dict['det']


# 计算vehicle的最小外接矩形中心点之间的距离和距离得分
def vehicleDistance2(normVehicleCOOR, traffic_dict, vehicleWH):
    if len(normVehicleCOOR) > 1:  # 有多辆车
        for b in range(len(normVehicleCOOR)):
            centerDistance = []  # 存储contours之间的最短距离
            tmp = normVehicleCOOR[b]
            normVehicleCOOR[b] = normVehicleCOOR[0]
            normVehicleCOOR[0] = tmp
            for c in range(1, len(normVehicleCOOR)):
                centerDistance.append(two_points_distance(normVehicleCOOR[0][0], normVehicleCOOR[0][1], normVehicleCOOR[c][0], normVehicleCOOR[c][1]))
            smallestDistance = min(centerDistance)
            index = centerDistance.index(smallestDistance)
            traffic_dict['det'][b][8] = smallestDistance
            if index == b - 1:  # 序号0和b对应的vehicle
                traffic_dict['det'] = distanceScore(vehicleWH, 0, b, smallestDistance, traffic_dict)
            else:
                traffic_dict['det'] = distanceScore(vehicleWH, index+1, b, smallestDistance, traffic_dict)
            tmp = normVehicleCOOR[b]
            normVehicleCOOR[b] = normVehicleCOOR[0]
            normVehicleCOOR[0] = tmp
    else:  # 路上只有一辆车
        if max(traffic_dict['det'][0][9]) == traffic_dict['det'][0][9][0] and traffic_dict['det'][0][9][0] != -1:
            traffic_dict['det'][0][10] = 0
        elif max(traffic_dict['det'][0][9]) == traffic_dict['det'][0][9][1] and traffic_dict['det'][0][9][1] != -1:
            traffic_dict['det'][0][10] = 1
        else:
            traffic_dict['det'][0][10] = 3
    return traffic_dict['det']


def PostProcessing( traffic_dict):
    """
    对于字典traffic_dict中的各个键，说明如下：
    RoadArea：speedRoad的最小外接矩形的面积
    roadVehicleAngle：判定发生交通事故的speedRoad与vehicle间的最小夹角
    vehicleCOOR：是一个列表，用于存储被检测出的vehicle的坐标（vehicle检测模型）
    roundness：长宽比 ,vehicle的长与宽的比率，设置为0.7，若宽与长的比值大于0.7，则判定该vehicle发生交通事故
    ZoomFactor：存储的是图像在H和W方向上的缩放因子，其值小于1
    'cls':类别号
    'vehicleFactor':两辆车之间的安全距离被定义为：min(车辆1的宽，车辆2的宽) * vehicleFactor
    'radius'：半径，以某一vehicle的最小外接矩形的中点为圆心，以radius为半径，划定范围，过滤车辆
    'distanceFlag'：开关。计算vehicle之间的距离时，可选择不同的函数
    'vehicleFlag'：开关。存储vehicle的信息时，可选择不同的函数
    未发生交通事故时，得分为-1，”事故类型“为3
    最终输出格式：[[cls, x0, y0, x1, y1, score, 角度, 长宽比, 最小距离, max([角度得分, 长宽比得分, 最小距离得分]), 交通事故类别], ...]
    交通事故类别：0表示角度，1表示长宽比，2表示最短距离，3表示未发生交通事故
    """
    
    det_cors = []
    #print('###line338:', traffic_dict['det'])
    for bb in traffic_dict['det']:
        det_cors.append((int(bb[1]), int(bb[2])))
        det_cors.append((int(bb[3]), int(bb[4])))
    traffic_dict['vehicleCOOR'] = det_cors
    

    #testImageArray = testImageArray[:, :, 0]
    #H, W = testImageArray.shape[0:2]  # sourceImage的分辨率为1080x1920
    
    traffic_dict['modelSize']=[640,360]
    #traffic_dict['mask'] = cv2.resize(traffic_dict['mask'],(640,360))
    
    mask = traffic_dict['mask']
    H, W = mask.shape[0:2]
    #(640, 360) 720 1280 (720, 1280)
    ####line361: (1920, 1080) 720 1280 (720, 1280)
    
    ###line361: [640, 360] 360 640 (360, 640)

    
    
    #print('###line361:',traffic_dict['modelSize'], H,W ,mask.shape)
    
    scaleH = traffic_dict['modelSize'][1] / H  # 自适应调整缩放比例
    scaleW = traffic_dict['modelSize'][0] / W
    traffic_dict['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]

    t1 = time.time()
    normVehicleBD = []  # 存储一副图像中合格vehicle的contours,合格vehicle，即：contours中的顶点数大于等于6
    imgRoad = mask.copy()
    imgVehicle = mask.copy()
    imgRoad[imgRoad == 2] = 0  # 将vehicle过滤掉，只包含背景和speedRoad
    imgVehicle[imgVehicle == 1] = 0  # 将speedRoad过滤掉，只包含背景和vehicle
    imgRoad = cv2.cvtColor(np.uint8(imgRoad), cv2.COLOR_RGB2BGR)  # 道路
    imgVehicle = cv2.cvtColor(np.uint8(imgVehicle), cv2.COLOR_RGB2BGR)  # 车辆

    t2 = time.time()
    img1 = cv2.cvtColor(imgRoad, cv2.COLOR_BGR2GRAY)
    contours, hierarchy = cv2.findContours(img1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    t3 = time.time()

    allRoadContent = []  # 存放所有的speedRoad信息，单个speedRoad的信息为：[cnt, speedRoadAngle, rect[1]]
    vehicleBox = []  # 存储合格vehicle的box参数，合格vehicle,即：contours顶点个数大于等于6
    vehicleWH = []  # 存储合格vehicle的宽高
    normVehicle = []  # 存储合格vehicle的信息
    unnormVehicle = []  # 存储不合格vehicle的信息，不合格vehicle,即：contours顶点个数小于6
    normVehicleCOOR = []  # 存储合格vehicle的中心点坐标
    allRoadContent = storageRoad(contours, allRoadContent, traffic_dict)
    t4 = time.time()

    # 开关。存储vehicle的信息时，可选择不同的函数
    if traffic_dict['vehicleFlag'] == True:
        traffic_dict['det'], normVehicleBD, unnormVehicle, normVehicleCOOR = storageVehicle1(traffic_dict, normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR, imgVehicle)
        #所有车辆的[cls,x0,y0,x1,y1,score]
    else:
        traffic_dict['det'], normVehicleBD, unnormVehicle, normVehicleCOOR = storageVehicle2(traffic_dict, normVehicleBD, normVehicle, unnormVehicle, normVehicleCOOR, imgVehicle)
    t5 = time.time()
    if len(normVehicleBD) != 0:
        t6 = time.time()
        vehicleBox, vehicleWH, traffic_dict['det'] = angleRoundness(normVehicleBD, vehicleBox, vehicleWH, allRoadContent, traffic_dict, normVehicleCOOR, imgVehicle)
        t7 = time.time()
        # 开关。计算vehicle之间的距离时，可选择不同的函数
        if traffic_dict['distanceFlag'] == True:
            traffic_dict['det'] = vehicleDistance1(normVehicleCOOR, normVehicleBD, traffic_dict, vehicleWH)
        else:
            traffic_dict['det'] = vehicleDistance2(normVehicleCOOR, traffic_dict, vehicleWH)
        t8 = time.time()
        targetList = traffic_dict['det']
        # print("line393", targetList)
        for i in range(len(targetList)):
            targetList[i][9] = max(targetList[i][9])
        if len(unnormVehicle) != 0:
            targetList = targetList + unnormVehicle
        t9 = time.time()
        # print("line462", targetList)  # 目标对象list, [[cls, x0, y0, x1, y1, score, 角度, 长宽比, 最小距离, max([角度得分, 长宽比得分, 最小距离得分]), 类别], ...]
        ruleJudge='angle-rundness-distance:%.1f'%( get_ms(t9,t6) )
    else:
        targetList = unnormVehicle
        ruleJudge = 'No angle-rundness-distance judging'
    t10 = time.time()
    time_infos = '---test---nothing---'
    #time_infos = 'postTime:%.2f (分割时间：%.2f, findContours:%.2f, ruleJudge:%.2f, storageRoad:%.2f, storageVehicle:%.2f, angleRoundScore:%.2f, vehicleDistance:%.2f, mergeList:%.2f)' % (
    #    get_ms(t10, t1), get_ms(t2, t1), get_ms(t3, t2), get_ms(t10, t3), get_ms(t4, t3), get_ms(t5, t4), get_ms(t7, t6), get_ms(t8, t7), get_ms(t9, t8))
    time_infos = 'postTime:%.2f , ( findContours:%.1f , carContourFilter:%.1f, %s )' %( get_ms(t10,t1), get_ms(t4,t1), get_ms(t5,t4),ruleJudge)
    return targetList, time_infos


def TrafficPostProcessing(traffic_dict):
    """
    对于字典traffic_dict中的各个键，说明如下：
    RoadArea：speedRoad的最小外接矩形的面积
    spillsCOOR：是一个列表，用于存储被检测出的spill的坐标（spill检测模型）
    ZoomFactor：存储的是图像在H和W方向上的缩放因子，其值小于1
    'cls':类别号
    """
    traffic_dict['modelSize'] = [640, 360]
    mask = traffic_dict['mask']
    H, W = mask.shape[0:2]
    scaleH = traffic_dict['modelSize'][1] / H  # 自适应调整缩放比例
    scaleW = traffic_dict['modelSize'][0] / W
    traffic_dict['ZoomFactor'] = {'x': scaleH, 'y': scaleW}
    new_hw = [int(H * scaleH), int(W * scaleW)]
    t0 = time.time()
    mask = cv2.resize(mask, (new_hw[1], new_hw[0]))
    if len(mask.shape) == 3:
        mask = mask[:, :, 0]
    imgRoad = mask.copy()
    imgRoad[imgRoad == 2] = 0  # 将vehicle过滤掉，只包含背景和speedRoad
    imgRoad = cv2.cvtColor(np.uint8(imgRoad), cv2.COLOR_RGB2BGR)  # 道路
    imgRoad = cv2.cvtColor(imgRoad, cv2.COLOR_BGR2GRAY)  #
    contours, thresh = cv2.threshold(imgRoad, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # 寻找轮廓(多边界)
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_LIST, 2)
    contour_info = []
    for c in contours:
        contour_info.append((
            c,
            cv2.isContourConvex(c),
            cv2.contourArea(c),
        ))
    contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
    t1 = time.time()

    '''新增模块：：如果路面为空，则返回原图、无抛洒物等。'''
    if contour_info == []:
        # final_img=_img_cv
        timeInfos = 'road is empty   findContours:%.1f'%get_ms(t0,t1)

        return [], timeInfos
    else:
        # print(contour_info[0])
        max_contour = contour_info[0][0]
        max_contour[:,:,0] = (max_contour[:,:,0] / scaleW).astype(np.int32)  # contours恢复原图尺寸
        max_contour[:,:,1] = (max_contour[:,:,1] / scaleH).astype(np.int32)  # contours恢复原图尺寸

    '''3、preds中spillage，通过1中路面过滤'''
    init_spillage_filterroad = traffic_dict['det']
    final_spillage_filterroad = []
    for i in range(len(init_spillage_filterroad)):
        flag = xyxy_coordinate(init_spillage_filterroad[i],max_contour)
        if flag == 1:
            final_spillage_filterroad.append(init_spillage_filterroad[i])

    t2 = time.time()
    timeInfos = 'findContours:%.1f ,   carContourFilter:%.1f' % (get_ms(t0, t1), get_ms(t2, t1))

    return final_spillage_filterroad, timeInfos  # 返回最终绘制的结果图、最高速搞萨物（坐标、类别、置信度）

def tracfficAccidentMixFunction(preds,seg_pred_mulcls,pars):
    tjime0=time.time()
    roadIou =  pars['roadIou'] if 'roadIou' in pars.keys() else 0.5
    preds = np.array(preds)    
    #area_factors= np.array([np.sum(seg_pred_mulcls[int(x[2]):int(x[4]), int(x[1]):int(x[3])] )*1.0/(1.0*(x[3]-x[1])*(x[4]-x[2])+0.00001) for x in preds]  )
    area_factors= np.array([np.sum(seg_pred_mulcls[int(x[1]):int(x[3]), int(x[0]):int(x[2])] )*1.0/(1.0*(x[2]-x[0])*(x[3]-x[1])+0.00001) for x in preds]  )#2023.08.03修改数据格式
    water_flag = np.array(area_factors>roadIou) 
    #print('##line936:',preds )
    dets = preds[water_flag]##如果是水上目标，则需要与水的iou超过0.1；如果是岸坡目标，则直接保留。
    dets =  dets.tolist()
            
            
            
    #label_info = get_label_info(pars['label_csv'])  
    imH,imW = seg_pred_mulcls.shape[0:2]
    seg_pred = cv2.resize(seg_pred_mulcls,(   pars['modelSize'][0]  ,  pars['modelSize'] [1]) )
    mmH,mmW  = seg_pred.shape[0:2]

    fx=mmW/imW;fy=mmH/imH
    det_coords=[]

    det_coords_original=[]
    for box in dets:  
        #b_0 = box[1:5];b_0.insert(0,box[0]);b_0.append(box[5] )
        b_0 = box[0:4];b_0.insert(0,box[5]);b_0.append(box[4])
        det_coords_original.append( box )  
        if int(box[5]) != pars['CarId'] and int(box[5]) != pars['CthcId']: continue
        det_coords.append(b_0)
    #print('##line957:',det_coords_original )

    pars['ZoomFactor']={'x':mmW/imW  ,'y':mmH/imH}
    
    #pars['mask']=seg_pred;
    pars['mask']=seg_pred_mulcls;
    
    
    pars['det']=deepcopy(det_coords)
    #pars['label_info']=label_info
    tlist = list(pars.keys()); tlist.sort()
   
    if len(det_coords)> 0:
        #print('###line459:',pars['mask'].shape, pars['det'])
        list8,time_infos = PostProcessing(pars) 
        #print('###line461:',list8 )
        Accident_results = np.array(list8,dtype=object)  
        acc_det=[]
        #[1.0, 1692.0, 169.0, 1803.0, 221.0, 0.494875431060791, 30, 0.5, 3.0, 0.3, 0]
        #[0  ,     1 ,   2  ,    3  ,   4  ,         5        ,  6, 7  ,  8 , 9  , 10]
        for bpoints in list8:
            if bpoints[9]>pars['confThres']:
                xyxy=bpoints[1:5];xyxy=[int(x) for x in xyxy]
                
                cls=pars['cls'];conf=bpoints[9];
                box_acc = [*xyxy,conf,cls]
                acc_det.append(box_acc)
                #if cls  in allowedList:
                #    p_result[1] = draw_painting_joint(xyxy,p_result[1],label_arraylist[int(cls)],score=conf,color=rainbows[int(cls)%20],font=font,socre_location="leftBottom")
        #print('###line475:',acc_det )        
        #去掉被定为事故的车辆
        carCorslist = [  [  int(x[0]),int(x[1]), int(x[2]), int(x[3])    ] for x in det_coords_original ]   
        #print('##line81:',det_coords_original )
        accidentCarIndexs = [ carCorslist.index( [ int(x[0]),int(x[1]), int(x[2]), int(x[3])  ] )  for x in  acc_det ]
        accidentCarIndexsKeep = set(list(range(len(det_coords_original)))) - set(accidentCarIndexs)
        det_coords_original_tmp = [ det_coords_original[x] for x in accidentCarIndexsKeep ]
        det_coords_original = det_coords_original_tmp
        #print('##line85:',det_coords_original )
        det_coords_original.extend(acc_det)  
        #4.0, 961.0, 275.0, 1047.0, 288.0, 0.26662659645080566, 0.0, 0.0
        #0   ,  1  ,   2  ,    3  ,   4  ,         5          ,  6 ,  7
        #det_coords_original =[ [ *x[1:6], x[0],*x[6:8] ] for x in  det_coords_original]
    else:
        time_infos=" no tracfficAccidentMix process"
 
    #p_result[2]=  deepcopy(det_coords_original)
    return   deepcopy(det_coords_original),time_infos
def tracfficAccidentMixFunction_N(predList,pars):   
    preds,seg_pred_mulcls = predList[0:2]
    return tracfficAccidentMixFunction(preds,seg_pred_mulcls,pars)

def mixTraffic_postprocess(preds, seg_pred_mulcls,pars=None):
    '''输入：路面上的结果（类别+坐标）、原图、mask图像
       过程：获得mask的轮廓，判断抛洒物是否在轮廓内。
            在，则保留且绘制；不在，舍弃。
       返回：最终绘制的结果图、最终路面上物体（坐标、类别、置信度），
    '''
    '''1、最大分隔路面作为判断依据'''
    roadIou = pars['roadIou'] if 'roadIou' in pars.keys() else 0.5
    preds = np.array(preds)
    area_factors = np.array([np.sum(seg_pred_mulcls[int(x[1]):int(x[3]), int(x[0]):int(x[2])]) * 1.0 / (
                1.0 * (x[2] - x[0]) * (x[3] - x[1]) + 0.00001) for x in preds])  # 2023.08.03修改数据格式
    water_flag = np.array(area_factors > roadIou)
    dets = preds[water_flag]  ##如果是水上目标，则需要与水的iou超过0.1；如果是岸坡目标，则直接保留。
    dets = dets.tolist()

    imH, imW = seg_pred_mulcls.shape[0:2]
    seg_pred = cv2.resize(seg_pred_mulcls, (pars['modelSize'][0], pars['modelSize'][1]))
    mmH, mmW = seg_pred.shape[0:2]

    fx = mmW / imW;
    fy = mmH / imH
    det_coords = []

    for box in dets:
        if int(box[5]) != pars['cls']: continue
        det_coords.append(box)

    pars['ZoomFactor'] = {'x': mmW / imW, 'y': mmH / imH}
    pars['mask'] = seg_pred_mulcls;

    pars['det'] = deepcopy(det_coords)

    if len(det_coords) > 0:
        # print('###line459:',pars['mask'].shape, pars['det'])
        return  TrafficPostProcessing(pars)

    else:
        return [], 'no spills find in road'