| |
| import numpy as np |
| from skimage import io |
| import matplotlib.pyplot as plt |
| import cv2 as cv |
| from skimage.morphology import skeletonize |
| from skimage.morphology import erosion, dilation, disk |
| from skimage.measure import label |
|
|
| import os |
| import sys |
| from tqdm import tqdm |
| from glob import glob |
| import pickle as pkl |
|
|
| def filter_bdy_cond(bdy_, mask, cond): |
|
|
| cond = cv.dilate(cond.astype(np.uint8),disk(1)) |
| labels = label(mask) |
| lbls = np.unique(labels) |
| indep = np.ones(lbls.shape[0]) |
| indep[0] = 0 |
|
|
| boundaries = [] |
| h,w = cond.shape[0:2] |
| ind_map = np.zeros((h,w)) |
| indep_cnt = 0 |
|
|
| for i in range(0,len(bdy_)): |
| tmp_bdies = [] |
| tmp_bdy = [] |
| for j in range(0,bdy_[i].shape[0]): |
| r, c = bdy_[i][j,0,1],bdy_[i][j,0,0] |
|
|
| if(np.sum(cond[r,c])==0 or ind_map[r,c]!=0): |
| if(len(tmp_bdy)>0): |
| tmp_bdies.append(tmp_bdy) |
| tmp_bdy = [] |
| continue |
| tmp_bdy.append([c,r]) |
| ind_map[r,c] = ind_map[r,c] + 1 |
| indep[labels[r,c]] = 0 |
| if(len(tmp_bdy)>0): |
| tmp_bdies.append(tmp_bdy) |
|
|
| |
| |
| if(len(tmp_bdies)>1): |
| first_x, first_y = tmp_bdies[0][0] |
| last_x, last_y = tmp_bdies[-1][-1] |
| if((abs(first_x-last_x)==1 and first_y==last_y) or |
| (first_x==last_x and abs(first_y-last_y)==1) or |
| (abs(first_x-last_x)==1 and abs(first_y-last_y)==1) |
| ): |
| tmp_bdies[-1].extend(tmp_bdies[0][::-1]) |
| del tmp_bdies[0] |
|
|
| for k in range(0,len(tmp_bdies)): |
| tmp_bdies[k] = np.array(tmp_bdies[k])[:,np.newaxis,:] |
| if(len(tmp_bdies)>0): |
| boundaries.extend(tmp_bdies) |
|
|
| return boundaries, np.sum(indep) |
|
|
| |
| |
| def approximate_RDP(boundaries,epsilon=1.0): |
|
|
| boundaries_ = [] |
| boundaries_len_ = [] |
| pixel_cnt_ = 0 |
|
|
| |
| for i in range(0,len(boundaries)): |
| boundaries_.append(cv.approxPolyDP(boundaries[i],epsilon,False)) |
|
|
| |
| for i in range(0,len(boundaries_)): |
| boundaries_len_.append(len(boundaries_[i])) |
| pixel_cnt_ = pixel_cnt_ + len(boundaries_[i]) |
|
|
| return boundaries_, boundaries_len_, pixel_cnt_ |
|
|
|
|
| def relax_HCE(gt, rs, gt_ske, relax=5, epsilon=2.0): |
| |
| |
| |
|
|
| |
| if(len(gt.shape)>2): |
| gt = gt[:,:,0] |
|
|
| epsilon_gt = 128 |
| gt = (gt>epsilon_gt).astype(np.uint8) |
|
|
| |
| if(len(rs.shape)>2): |
| rs = rs[:,:,0] |
| epsilon_rs = 128 |
| rs = (rs>epsilon_rs).astype(np.uint8) |
|
|
| Union = np.logical_or(gt,rs) |
| TP = np.logical_and(gt,rs) |
| FP = rs - TP |
| FN = gt - TP |
|
|
| |
| Union_erode = Union.copy() |
| Union_erode = cv.erode(Union_erode.astype(np.uint8),disk(1),iterations=relax) |
|
|
| |
| FP_ = np.logical_and(FP,Union_erode) |
| for i in range(0,relax): |
| FP_ = cv.dilate(FP_.astype(np.uint8),disk(1)) |
| FP_ = np.logical_and(FP_, 1-np.logical_or(TP,FN)) |
| FP_ = np.logical_and(FP, FP_) |
|
|
| |
| FN_ = np.logical_and(FN,Union_erode) |
| |
| for i in range(0,relax): |
| FN_ = cv.dilate(FN_.astype(np.uint8),disk(1)) |
| FN_ = np.logical_and(FN_,1-np.logical_or(TP,FP)) |
| FN_ = np.logical_and(FN,FN_) |
| FN_ = np.logical_or(FN_, np.logical_xor(gt_ske,np.logical_and(TP,gt_ske))) |
|
|
| |
| |
| ctrs_FP, hier_FP = cv.findContours(FP_.astype(np.uint8), cv.RETR_TREE, cv.CHAIN_APPROX_NONE) |
| |
| bdies_FP, indep_cnt_FP = filter_bdy_cond(ctrs_FP, FP_, np.logical_or(TP,FN_)) |
| |
| ctrs_FN, hier_FN = cv.findContours(FN_.astype(np.uint8), cv.RETR_TREE, cv.CHAIN_APPROX_NONE) |
| |
| bdies_FN, indep_cnt_FN = filter_bdy_cond(ctrs_FN, FN_, 1-np.logical_or(np.logical_or(TP,FP_),FN_)) |
|
|
| poly_FP, poly_FP_len, poly_FP_point_cnt = approximate_RDP(bdies_FP,epsilon=epsilon) |
| poly_FN, poly_FN_len, poly_FN_point_cnt = approximate_RDP(bdies_FN,epsilon=epsilon) |
|
|
| return poly_FP_point_cnt, indep_cnt_FP, poly_FN_point_cnt, indep_cnt_FN |
|
|
| def compute_hce(pred_root,gt_root,gt_ske_root): |
|
|
| gt_name_list = glob(pred_root+'/*.png') |
| gt_name_list = sorted([x.split('/')[-1] for x in gt_name_list]) |
|
|
| hces = [] |
| for gt_name in tqdm(gt_name_list, total=len(gt_name_list)): |
| gt_path = os.path.join(gt_root, gt_name) |
| pred_path = os.path.join(pred_root, gt_name) |
|
|
| gt = cv.imread(gt_path, cv.IMREAD_GRAYSCALE) |
| pred = cv.imread(pred_path, cv.IMREAD_GRAYSCALE) |
|
|
| ske_path = os.path.join(gt_ske_root,gt_name) |
| if os.path.exists(ske_path): |
| ske = cv.imread(ske_path,cv.IMREAD_GRAYSCALE) |
| ske = ske>128 |
| else: |
| ske = skeletonize(gt>128) |
|
|
| FP_points, FP_indep, FN_points, FN_indep = relax_HCE(gt, pred,ske) |
| print(gt_path.split('/')[-1],FP_points, FP_indep, FN_points, FN_indep) |
| hces.append([FP_points, FP_indep, FN_points, FN_indep, FP_points+FP_indep+FN_points+FN_indep]) |
|
|
| hce_metric ={'names': gt_name_list, |
| 'hces': hces} |
|
|
|
|
| file_metric = open(pred_root+'/hce_metric.pkl','wb') |
| pkl.dump(hce_metric,file_metric) |
| |
| file_metric.close() |
|
|
| return np.mean(np.array(hces)[:,-1]) |
|
|
| def main(): |
|
|
| gt_root = "../DIS5K/DIS-VD/gt" |
| gt_ske_root = "" |
| pred_root = "../Results/isnet(ours)/DIS-VD" |
|
|
| print("The average HCE metric: ", compute_hce(pred_root,gt_root,gt_ske_root)) |
|
|
|
|
| if __name__ == '__main__': |
| main() |
|
|