-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheval_cam_brats.py
More file actions
270 lines (244 loc) · 11 KB
/
Copy patheval_cam_brats.py
File metadata and controls
270 lines (244 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
from collections import defaultdict
import cv2
import numpy as np
import os
from PIL import Image
import argparse
from scipy.spatial.distance import directed_hausdorff
from scipy.spatial.distance import cdist
from medpy.metric.binary import hd95
# def hd95(pred, true, distance="euclidean"):
# pred_points = np.argwhere(pred > 0)
# true_points = np.argwhere(true > 0)
#
# if len(pred_points) == 0 or len(true_points) == 0:
# return np.nan
#
# # 计算从预测到真实标签的最小距离
# forward_distances = cdist(pred_points, true_points, metric=distance).min(axis=1)
# # 计算从真实标签到预测的最小距离
# backward_distances = cdist(true_points, pred_points, metric=distance).min(axis=1)
#
# # 合并所有的距离,并计算 95% 分位数
# all_distances = np.concatenate([forward_distances, backward_distances])
# hd95_value = np.percentile(all_distances, 95)
# return hd95_value
def print_iou(iou, dname='voc'):
iou_dict = {}
for i in range(len(iou)-1):
iou_dict[i] = iou[i+1]
print(iou_dict)
return iou_dict
def _fast_hist(label_true, label_pred, n_class):
mask = (label_true >= 0) & (label_true < n_class)
hist = np.bincount(
n_class * label_true[mask].astype(int) + label_pred[mask],
minlength=n_class ** 2,
).reshape(n_class, n_class)
return hist
def dice_coeff(pred,target):
smooth = 1e-5
m1=pred.flatten()
m2=target.flatten()
intersection=(m1*m2).sum()
return (2. * intersection + smooth) / (m1.sum() + m2.sum() + smooth)
# def scores(label_trues, label_preds, n_class):
# hist = np.zeros((n_class, n_class))
# for lt, lp in zip(label_trues, label_preds):
# hist += _fast_hist(lt.flatten(), lp.flatten(), n_class)
# acc = np.diag(hist).sum() / hist.sum()
# acc_cls = np.diag(hist) / hist.sum(axis=1)
# acc_cls = np.nanmean(acc_cls)
# iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist))
# valid = hist.sum(axis=1) > 0 # added
# mean_iu = np.nanmean(iu[valid])
# freq = hist.sum(axis=1) / hist.sum()
# fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()
# cls_iu = dict(zip(range(n_class), iu))
#
# return {
# "Pixel Accuracy": acc,
# "Mean Accuracy": acc_cls,
# "Frequency Weighted IoU": fwavacc,
# "Mean IoU": mean_iu,
# "Class IoU": cls_iu,
# }
# def scores(label_trues, label_preds, n_class):
# hist = np.zeros((n_class, n_class))
# dice_scores = []
#
# for lt, lp in zip(label_trues, label_preds):
# hist += _fast_hist(lt.flatten(), lp.flatten(), n_class)
# # 计算 Dice 系数
# dice = dice_coeff(lt, lp)
# dice_scores.append(dice)
#
# acc = np.diag(hist).sum() / hist.sum()
# acc_cls = np.diag(hist) / hist.sum(axis=1)
# acc_cls = np.nanmean(acc_cls)
# iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist))
# valid = hist.sum(axis=1) > 0 # added
# mean_iu = np.nanmean(iu[valid])
# freq = hist.sum(axis=1) / hist.sum()
# fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()
# cls_iu = dict(zip(range(n_class), iu))
#
# return {
# "Pixel Accuracy": acc,
# "Mean Accuracy": acc_cls,
# "Frequency Weighted IoU": fwavacc,
# "Mean IoU": mean_iu,
# "Class IoU": cls_iu,
# "mean Dice Scores": np.array(dice_scores).mean(), # 添加 Dice 系数
# }
def iou_score(predict: np.ndarray, label: np.ndarray):
# 确保是二值化的,背景为0,目标区域为1
# 计算交集和并集
intersection = np.sum(predict * label)
union = np.sum(predict) + np.sum(label) - intersection
# 计算 IoU,避免除以零
if union == 0:
return np.nan # 或者返回 0, 具体根据需求调整
return intersection / union
def scores(label_trues, label_preds, eval_list, n_class):
hist = np.zeros((n_class, n_class))
sample_hist = defaultdict(lambda: np.zeros((n_class, n_class)))
dice_scores = []
hd95_scores = [] # 用于记录每对预测和真实标签的 HD95 值
sample_dice_scores = defaultdict(list) # 按样例存储 Dice 得分
sample_hd95_scores = defaultdict(list) # 按样例存储 HD95 得分
sample_iou_scores = defaultdict(list)
# 对每个样例的 hist 计算各类指标
sample_acc = []
sample_acc_cls = []
sample_mean_iu = []
sample_freq_wavacc = []
for lt, lp, lpath in zip(label_trues, label_preds, eval_list):
sample_name = lpath.split('/')[-2].split('_')[0]
hist += _fast_hist(lt.flatten(), lp.flatten(), n_class)
sample_hist[sample_name] += _fast_hist(lt.flatten(), lp.flatten(), n_class)
# 计算 Dice 系数
dice = dice_coeff(lt, lp)
dice_scores.append(dice)
sample_dice_scores[sample_name].append(dice)
ioutmp = iou_score(lt,lp)
sample_iou_scores[sample_name].append(ioutmp)
# 使用 MedPy 计算 HD95
try:
hd95_value = hd95(lp, lt)
except:
hd95_value = 344
hd95_scores.append(hd95_value)
sample_hd95_scores[sample_name].append(hd95_value)
for sample_hist_val in sample_hist.values():
acc = np.diag(sample_hist_val).sum() / sample_hist_val.sum()
sample_acc.append(acc)
acc_cls = np.diag(sample_hist_val) / sample_hist_val.sum(axis=1)
sample_acc_cls.append(np.nanmean(acc_cls))
iu = np.diag(sample_hist_val) / (sample_hist_val.sum(axis=1) + sample_hist_val.sum(axis=0) - np.diag(sample_hist_val))
valid = sample_hist_val.sum(axis=1) > 0
sample_mean_iu.append(np.nanmean(iu[valid]))
freq = sample_hist_val.sum(axis=1) / sample_hist_val.sum()
sample_freq_wavacc.append((freq[freq > 0] * iu[freq > 0]).sum())
acc = np.diag(hist).sum() / hist.sum()
acc_cls = np.diag(hist) / hist.sum(axis=1)
acc_cls = np.nanmean(acc_cls)
iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) - np.diag(hist))
valid = hist.sum(axis=1) > 0
mean_iu = np.nanmean(iu[valid])
freq = hist.sum(axis=1) / hist.sum()
# 对每个样例的得分进行平均计算
mean_dice_scores = {k: np.nanmean(v) for k, v in sample_dice_scores.items()}
mean_hd95_scores = {k: np.nanmean(v) for k, v in sample_hd95_scores.items()}
mean_iou_scores = {k: np.nanmean(v) for k, v in sample_iou_scores.items()}
# 计算所有样例的平均 Dice 和 HD95
overall_mean_dice = np.nanmean(list(mean_dice_scores.values()))
overall_mean_hd95 = np.nanmean(list(mean_hd95_scores.values()))
overall_mean_iou = np.nanmean(list(mean_iou_scores.values()))
return {
# "Pixel Accuracy": acc,
# "Mean Accuracy": acc_cls,
# "Mean IoU": mean_iu,
# "mean Dice Scores": np.array(dice_scores).mean(),
# "mean HD95": np.nanmean(hd95_scores),
"Sample-wise Mean Dice Scores": overall_mean_dice,
"Sample-wise Mean HD95": overall_mean_hd95,
# "Sample-wise Pixel Accuracy": np.nanmean(sample_acc),
# "Sample-wise Mean Accuracy": np.nanmean(sample_acc_cls),
"Sample-wise Mean IoU": overall_mean_iou,
# "Sample-wise Frequency Weighted IoU": np.nanmean(sample_freq_wavacc),
}
def run_eval_cam(args, print_log=True, is_coco=False):
preds = []
labels = []
n_images = 0
for i, id in enumerate(eval_list):
n_images += 1
if args.cam_type == 'png':
label_path = os.path.join(args.cam_out_dir, id + '.png')
cls_labels = np.asarray(Image.open(label_path), dtype=np.uint8)
else:
cam_dict = np.load(id, allow_pickle=True)['caa_sam1_stack_pred']
# cam_dict = np.array(Image.open(os.path.join('E:\\', id.split('/')[-1].split('.')[0] + '.jpg')))
cam_dict[cam_dict>0]=1
# cams = cam_dict['caa_sam1_stack_pred']
# if 'bg' not in args.cam_type:
# if args.cam_eval_thres < 1:
# cams = np.pad(cams, ((1, 0), (0, 0), (0, 0)), mode='constant', constant_values=args.cam_eval_thres)
# else:
# bg_score = np.power(1 - np.max(cams, axis=0, keepdims=True), args.cam_eval_thres)
# cams = np.concatenate((bg_score, cams), axis=0)
# keys = np.array([0,1])
# cls_labels = np.argmax(cams, axis=0)
# cls_labels = keys[cls_labels].astype(np.uint8)
cls_labels = cam_dict
preds.append(cv2.resize(cls_labels, (240, 240), interpolation=cv2.INTER_AREA))
gt_file = os.path.join(args.gt_root, id.split('/')[-1])
gt = np.array(np.load(gt_file)['arr_0']).astype(np.uint8)
gt[gt > 0] = 1
labels.append(cv2.resize(gt, (240, 240), interpolation=cv2.INTER_AREA))
iou = scores(labels, preds, eval_list,n_class=2)
if print_log:
print(iou)
return iou["Sample-wise Mean IoU"]
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--cam_out_dir", default="/root/data1/brats/2025消融实验0.7有2次SAM", type=str)
parser.add_argument("--cam_type", default="caa_sam1_stack_pred", type=str)
parser.add_argument('--img_root', type=str, default='/root/data1/brats/val/image')
parser.add_argument("--split_file", default="/home/xxx/datasets/VOC2012/ImageSets/Segmentation/train.txt", type=str)
parser.add_argument("--cam_eval_thres", default=2, type=float)
parser.add_argument("--gt_root", default="/root/data1/brats/val/label", type=str)
args = parser.parse_args()
eval_list=[]
is_coco = False
eval = os.listdir(args.cam_out_dir)
for brats in eval:
eval_list.append(os.path.join(args.cam_out_dir,brats))
if 'bg' in args.cam_type or 'png' in args.cam_type:
iou = run_eval_cam(args, True)
else:
if args.cam_eval_thres < 1:
thres_list = [0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6]
else:
if 'attn' in args.cam_type:
thres_list = [1, 2]
else:
thres_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
max_iou = 0
max_thres = 0
for thres in thres_list:
args.cam_eval_thres = thres
iou = run_eval_cam(args, print_log=True, is_coco=is_coco)
print(thres, iou)
if iou > max_iou:
max_iou = iou
max_thres = thres
args.cam_eval_thres = max_thres
iou = run_eval_cam(args, print_log=True, is_coco=False)
# args.cam_eval_thres = max_thres
# iou = run_eval_cam(args, print_log=True, is_coco=is_coco)
# --cam_out_dir /root/data1/CLIP-ES-main/output/brats/cams --cam_type attn_highres --gt_root /root/data1/brats/val/label --split_file ./voc12/train.txt
# --cam_out_dir C:/Users/Administrator/Desktop/rrrr/med/cams --cam_type caa_sam1_stack_pred --gt_root F:/brats/Train_Sets/val/val/label --split_file ./voc12/train.txt
# --cam_out_dir E:/rrrr --cam_type caa_sam1_stack_pred --gt_root F:/brats/val/label --split_file ./voc12/train.txt
# --cam_out_dir E:/rrrr --cam_type caa_sam1_stack_pred --gt_root F:/brats/val/label --split_file ./voc12/train.txt