|
|
|
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() |
|
|