import numpy as np
import time,cv2
def ms(t1,t0):
    return (t1-t0)*1000.0
def center_coordinate(boundbxs):
    '''
    输入：两个对角坐标xyxy
    输出：矩形框重点坐标xy
    '''
    boundbxs_x1=boundbxs[0]
    boundbxs_y1=boundbxs[1]
    boundbxs_x2=boundbxs[2]
    boundbxs_y2=boundbxs[3]
    center_x=0.5*(boundbxs_x1+boundbxs_x2)
    center_y=0.5*(boundbxs_y1+boundbxs_y2)
    return center_x,center_y

def fourcorner_coordinate(boundbxs):
    '''
    输入：两个对角坐标xyxy
    输出：矩形框四个角点坐标，以contours顺序。
    '''
    boundbxs_x1=boundbxs[0]
    boundbxs_y1=boundbxs[1]
    boundbxs_x2=boundbxs[2]
    boundbxs_y2=boundbxs[3]
    wid=boundbxs_x2-boundbxs_x1
    hei=boundbxs_y2-boundbxs_y1
    boundbxs_x3=boundbxs_x1+wid
    boundbxs_y3=boundbxs_y1
    boundbxs_x4=boundbxs_x1
    boundbxs_y4 = boundbxs_y1+hei
    contours_rec=[[boundbxs_x1,boundbxs_y1],[boundbxs_x3,boundbxs_y3],[boundbxs_x2,boundbxs_y2],[boundbxs_x4,boundbxs_y4]]
    return contours_rec

def remove_simivalue(list1,list2):
    '''
    将list1中属于list2的元素都删除。
    输入：两个嵌套列表
    返回：嵌套列表
    '''
    list33=list1.copy()
    for i in range(len(list1)):
        for j in range(len(list2)):
            if list2[j] == list1[i]:
                # list33.pop(list1[i])
                list33.remove(list1[i])
    return list33

def remove_sameeleme_inalist(list3):
    '''
    将list3中重复嵌套列表元素删除。
    输入：嵌套列表
    返回：嵌套列表
    '''
    list3=list3
    list4=[]
    list4.append(list3[0])
    for dict in list3:
        k=0
        for item in list4:
            if dict!=item:
                k=k+1
            else:
                break
            if k==len(list4):
                list4.append(dict)
    return list4

def order_points(pts):
    ''' sort rectangle points by clockwise '''
    sort_x = pts[np.argsort(pts[:, 0]), :]

    Left = sort_x[:2, :]
    Right = sort_x[2:, :]
    # Left sort
    Left = Left[np.argsort(Left[:, 1])[::-1], :]
    # Right sort
    Right = Right[np.argsort(Right[:, 1]), :]
    return np.concatenate((Left, Right), axis=0)

def mixDrowing_water_postprocess(preds,_mask_cv,pars ):
    '''考虑船上人过滤'''
    '''输入：落水人员的结果（类别+坐标）、原图、mask图像
       过程：获得mask的轮廓，判断人员是否在轮廓内。
            在，则保留且绘制；不在，舍弃。
       返回：最终绘制的结果图、最终落水人员（坐标、类别、置信度），
    '''
    '''1、最大分割水域作为判断依据'''
    #zoom_factor=4 #缩小因子设置为4，考虑到numpy中分别遍历xy进行缩放耗时大。
    original_height = _mask_cv.shape[0]
    original_width=_mask_cv.shape[1]
    
    zoom_factor = original_width/480.0
    
    zoom_height=int(original_height/zoom_factor)
    zoom_width=int(original_width/zoom_factor)

    _mask_cv = cv2.resize(_mask_cv, (zoom_width,zoom_height))  #缩小原图,宽在前，高在后
    t4 = time.time()
    img_gray = cv2.cvtColor(_mask_cv, cv2.COLOR_BGR2GRAY)  if len(_mask_cv.shape)==3 else _mask_cv    #
    t5 = time.time()
    contours, thresh = cv2.threshold(img_gray, 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)
    t6 = time.time()

    '''新增模块：：如果水域为空，则返回原图、无落水人员等。'''
    if contour_info==[]:
        # final_img=_img_cv
        final_head_person_filterwater=[]
        timeInfos=0
        # return final_img, final_head_person_filterwater
        return final_head_person_filterwater,timeInfos
    else:
        max_contour = contour_info[0]
        max_contour=max_contour[0]*zoom_factor# contours恢复原图尺寸
        max_contour = max_contour.astype(np.int32)
        #print(max_contour)
    t7 = time.time()


    '''2.1、preds中head+person取出，boat取出。'''
    init_head_person=[]
    init_boat = []
    for i in range(len(preds)):
        if preds[i][5]==0 or preds[i][5]==1:
            init_head_person.append(preds[i])
        else:
            init_boat.append(preds[i])
    t8 = time.time()

    '''新增模块：2.2、preds中head+person取出，过滤掉head与person中指向同一人的部分，保留同一人的person标签。'''
    init_head=[]
    init_person=[]
    #head与person标签分开
    for i in range(len(init_head_person)):
        if init_head_person[i][5]==0:
            init_head.append(init_head_person[i])
        else:
            init_person.append(init_head_person[i])
    # person的框形成contours
    person_contour=[]
    for i in range(len(init_person)):
        boundbxs_temp=[init_person[i][0],init_person[i][1],init_person[i][2],init_person[i][3]]
        contour_temp_person=fourcorner_coordinate(boundbxs_temp) #得到person预测框的顺序contour
        contour_temp_person=np.array(contour_temp_person)
        contour_temp_person=np.float32(contour_temp_person)
        person_contour.append(np.array(contour_temp_person))
    # head是否在person的contours内，在说明是同一人，过滤掉。
    list_head=[]
    for i in range(len(init_head)):
        for j in range(len(person_contour)):
            center_x, center_y=center_coordinate(init_head[i])
            flag = cv2.pointPolygonTest(person_contour[j], (center_x, center_y), False) #若为False，会找点是否在内，外，或轮廓上(相应返回+1, -1, 0)。
            if flag==1:
                pass
            else:
                list_head.append(init_head[i])
    # person和最终head合并起来
    init_head_person_temp=init_person+list_head

    '''3、preds中head+person，通过1中水域过滤'''
    init_head_person_filterwater=init_head_person_temp
    final_head_person_filterwater=[]
    for i in range(len(init_head_person_filterwater)):
        center_x, center_y=center_coordinate(init_head_person_filterwater[i])
        #print('#'*20,'line176:',len(max_contour),np.array(max_contour).shape,(center_x, center_y))
        flag = cv2.pointPolygonTest(max_contour, (int(center_x), int(center_y)), False) #若为False，会找点是否在内，外，或轮廓上(相应返回+1, -1, 0)。
        if flag==1:
            final_head_person_filterwater.append(init_head_person_filterwater[i])
        else:
            pass
    t9 = time.time()

    '''4、水域过滤后的head+person，再通过船舶范围过滤'''
    init_head_person_filterboat=final_head_person_filterwater
    # final_head_person_filterboat=[]
    #获取船舶范围
    boat_contour=[]
    
    for i in range(len(init_boat)):
        boundbxs1=[init_boat[i][0],init_boat[i][1],init_boat[i][2],init_boat[i][3]]
        contour_temp=fourcorner_coordinate(boundbxs1) #得到boat预测框的顺序contour
        contour_temp_=np.array(contour_temp)
        contour_temp_=np.float32(contour_temp_)
        boat_contour.append(np.array(contour_temp_))
    t10 = time.time()
    # 遍历船舶范围，取出在船舶范围内的head和person（可能有重复元素）
    list_headperson_inboat=[]
    for i in range(len(init_head_person_filterboat)):
        for j in range(len(boat_contour)):
            center_x, center_y=center_coordinate(init_head_person_filterboat[i])
            # yyyyyyyy=boat_contour[j]
            flag = cv2.pointPolygonTest(boat_contour[j], (center_x, center_y), False) #若为False，会找点是否在内，外，或轮廓上(相应返回+1, -1, 0)。
            if flag==1:
                list_headperson_inboat.append(init_head_person_filterboat[i])
            else:
                pass
    # print('list_headperson_inboat',list_headperson_inboat)
    if len(list_headperson_inboat)==0:
        pass
    else:
        list_headperson_inboat=remove_sameeleme_inalist(list_headperson_inboat) #将重复嵌套列表元素删除
    # 过滤船舶范围内的head和person
    final_head_person_filterboat=remove_simivalue(init_head_person_filterboat,list_headperson_inboat)
    final_output_luoshui=final_head_person_filterboat
    t11 = time.time()

    #timeInfos=('存图:%s, 过滤标签:%s ,遍历船舶范围:%s,水域过滤后的head+person:%s,水域过滤:%s,head+person、boat取出:%s，新增如果水域为空:%s，找contours:%s，图像改变:%s'
    #      %((t11-t10) * 1000,(t10-t9) * 1000,(t9-t8) * 1000,(t8-t7) * 1000,(t7-t6) * 1000,(t6-t5) * 1000,(t5-t4) * 1000 ) )
    timeInfos=' findMaxWater:%.1f  releJudge:%.1f'%( ms(t6,t4) ,ms(t11,t6)  )
    return final_output_luoshui,timeInfos  #返回最终绘制的结果图、最终落水人员（坐标、类别、置信度）
def mixDrowing_water_postprocess_N(predList,pars ):
    preds,_mask_cv = predList[0:2]
    return mixDrowing_water_postprocess(preds,_mask_cv,pars )

