python-wml 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of python-wml might be problematic. Click here for more details.
- python_wml-3.0.0.dist-info/LICENSE +23 -0
- python_wml-3.0.0.dist-info/METADATA +51 -0
- python_wml-3.0.0.dist-info/RECORD +164 -0
- python_wml-3.0.0.dist-info/WHEEL +5 -0
- python_wml-3.0.0.dist-info/top_level.txt +1 -0
- wml/__init__.py +0 -0
- wml/basic_data_def/__init__.py +2 -0
- wml/basic_data_def/detection_data_def.py +279 -0
- wml/basic_data_def/io_data_def.py +2 -0
- wml/basic_img_utils.py +816 -0
- wml/img_patch.py +92 -0
- wml/img_utils.py +571 -0
- wml/iotoolkit/__init__.py +17 -0
- wml/iotoolkit/aic_keypoint.py +115 -0
- wml/iotoolkit/baidu_mask_toolkit.py +244 -0
- wml/iotoolkit/base_dataset.py +210 -0
- wml/iotoolkit/bboxes_statistics.py +515 -0
- wml/iotoolkit/build.py +0 -0
- wml/iotoolkit/cityscapes_toolkit.py +183 -0
- wml/iotoolkit/classification_data_statistics.py +25 -0
- wml/iotoolkit/coco_data_fwd.py +225 -0
- wml/iotoolkit/coco_keypoints.py +118 -0
- wml/iotoolkit/coco_keypoints_fmt2.py +103 -0
- wml/iotoolkit/coco_toolkit.py +397 -0
- wml/iotoolkit/coco_wholebody.py +269 -0
- wml/iotoolkit/common.py +108 -0
- wml/iotoolkit/crowd_pose.py +146 -0
- wml/iotoolkit/fast_labelme.py +110 -0
- wml/iotoolkit/image_folder.py +95 -0
- wml/iotoolkit/imgs_cache.py +58 -0
- wml/iotoolkit/imgs_reader_mt.py +73 -0
- wml/iotoolkit/labelme_base.py +102 -0
- wml/iotoolkit/labelme_json_to_img.py +49 -0
- wml/iotoolkit/labelme_toolkit.py +117 -0
- wml/iotoolkit/labelme_toolkit_fwd.py +733 -0
- wml/iotoolkit/labelmemckeypoints_dataset.py +169 -0
- wml/iotoolkit/lspet.py +48 -0
- wml/iotoolkit/mapillary_vistas_toolkit.py +269 -0
- wml/iotoolkit/mat_data.py +90 -0
- wml/iotoolkit/mckeypoints_statistics.py +28 -0
- wml/iotoolkit/mot_datasets.py +62 -0
- wml/iotoolkit/mpii.py +108 -0
- wml/iotoolkit/npmckeypoints_dataset.py +164 -0
- wml/iotoolkit/o365_to_coco.py +136 -0
- wml/iotoolkit/object365_toolkit.py +156 -0
- wml/iotoolkit/object365v2_toolkit.py +71 -0
- wml/iotoolkit/pascal_voc_data.py +51 -0
- wml/iotoolkit/pascal_voc_toolkit.py +194 -0
- wml/iotoolkit/pascal_voc_toolkit_fwd.py +473 -0
- wml/iotoolkit/penn_action.py +57 -0
- wml/iotoolkit/rawframe_dataset.py +129 -0
- wml/iotoolkit/rewrite_pascal_voc.py +28 -0
- wml/iotoolkit/semantic_data.py +49 -0
- wml/iotoolkit/split_file_by_type.py +29 -0
- wml/iotoolkit/sports_mot_datasets.py +78 -0
- wml/iotoolkit/vis_objectdetection_dataset.py +70 -0
- wml/iotoolkit/vis_torch_data.py +39 -0
- wml/iotoolkit/yolo_toolkit.py +38 -0
- wml/object_detection2/__init__.py +4 -0
- wml/object_detection2/basic_visualization.py +37 -0
- wml/object_detection2/bboxes.py +812 -0
- wml/object_detection2/data_process_toolkit.py +146 -0
- wml/object_detection2/keypoints.py +292 -0
- wml/object_detection2/mask.py +120 -0
- wml/object_detection2/metrics/__init__.py +3 -0
- wml/object_detection2/metrics/build.py +15 -0
- wml/object_detection2/metrics/classifier_toolkit.py +440 -0
- wml/object_detection2/metrics/common.py +71 -0
- wml/object_detection2/metrics/mckps_toolkit.py +338 -0
- wml/object_detection2/metrics/toolkit.py +1953 -0
- wml/object_detection2/npod_toolkit.py +361 -0
- wml/object_detection2/odtools.py +243 -0
- wml/object_detection2/standard_names.py +75 -0
- wml/object_detection2/visualization.py +956 -0
- wml/object_detection2/wmath.py +34 -0
- wml/semantic/__init__.py +0 -0
- wml/semantic/basic_toolkit.py +65 -0
- wml/semantic/mask_utils.py +156 -0
- wml/semantic/semantic_test.py +21 -0
- wml/semantic/structures.py +1 -0
- wml/semantic/toolkit.py +105 -0
- wml/semantic/visualization_utils.py +658 -0
- wml/threadtoolkit.py +50 -0
- wml/walgorithm.py +228 -0
- wml/wcollections.py +212 -0
- wml/wfilesystem.py +487 -0
- wml/wml_utils.py +657 -0
- wml/wstructures/__init__.py +4 -0
- wml/wstructures/common.py +9 -0
- wml/wstructures/keypoints_train_toolkit.py +149 -0
- wml/wstructures/kps_structures.py +579 -0
- wml/wstructures/mask_structures.py +1161 -0
- wml/wtorch/__init__.py +8 -0
- wml/wtorch/bboxes.py +104 -0
- wml/wtorch/classes_suppression.py +24 -0
- wml/wtorch/conv_module.py +181 -0
- wml/wtorch/conv_ws.py +144 -0
- wml/wtorch/data/__init__.py +16 -0
- wml/wtorch/data/_utils/__init__.py +45 -0
- wml/wtorch/data/_utils/collate.py +183 -0
- wml/wtorch/data/_utils/fetch.py +47 -0
- wml/wtorch/data/_utils/pin_memory.py +121 -0
- wml/wtorch/data/_utils/signal_handling.py +72 -0
- wml/wtorch/data/_utils/worker.py +227 -0
- wml/wtorch/data/base_data_loader_iter.py +93 -0
- wml/wtorch/data/dataloader.py +501 -0
- wml/wtorch/data/datapipes/__init__.py +1 -0
- wml/wtorch/data/datapipes/iter/__init__.py +12 -0
- wml/wtorch/data/datapipes/iter/batch.py +126 -0
- wml/wtorch/data/datapipes/iter/callable.py +92 -0
- wml/wtorch/data/datapipes/iter/listdirfiles.py +37 -0
- wml/wtorch/data/datapipes/iter/loadfilesfromdisk.py +30 -0
- wml/wtorch/data/datapipes/iter/readfilesfromtar.py +60 -0
- wml/wtorch/data/datapipes/iter/readfilesfromzip.py +63 -0
- wml/wtorch/data/datapipes/iter/sampler.py +94 -0
- wml/wtorch/data/datapipes/utils/__init__.py +0 -0
- wml/wtorch/data/datapipes/utils/common.py +65 -0
- wml/wtorch/data/dataset.py +354 -0
- wml/wtorch/data/datasets/__init__.py +4 -0
- wml/wtorch/data/datasets/common.py +53 -0
- wml/wtorch/data/datasets/listdirfilesdataset.py +36 -0
- wml/wtorch/data/datasets/loadfilesfromdiskdataset.py +30 -0
- wml/wtorch/data/distributed.py +135 -0
- wml/wtorch/data/multi_processing_data_loader_iter.py +866 -0
- wml/wtorch/data/sampler.py +267 -0
- wml/wtorch/data/single_process_data_loader_iter.py +24 -0
- wml/wtorch/data/test_data_loader.py +26 -0
- wml/wtorch/dataset_toolkit.py +67 -0
- wml/wtorch/depthwise_separable_conv_module.py +98 -0
- wml/wtorch/dist.py +591 -0
- wml/wtorch/dropblock/__init__.py +6 -0
- wml/wtorch/dropblock/dropblock.py +228 -0
- wml/wtorch/dropblock/dropout.py +40 -0
- wml/wtorch/dropblock/scheduler.py +48 -0
- wml/wtorch/ema.py +61 -0
- wml/wtorch/fc_module.py +73 -0
- wml/wtorch/functional.py +34 -0
- wml/wtorch/iter_dataset.py +26 -0
- wml/wtorch/loss.py +69 -0
- wml/wtorch/nets/__init__.py +0 -0
- wml/wtorch/nets/ckpt_toolkit.py +219 -0
- wml/wtorch/nets/fpn.py +276 -0
- wml/wtorch/nets/hrnet/__init__.py +0 -0
- wml/wtorch/nets/hrnet/config.py +2 -0
- wml/wtorch/nets/hrnet/hrnet.py +494 -0
- wml/wtorch/nets/misc.py +249 -0
- wml/wtorch/nets/resnet/__init__.py +0 -0
- wml/wtorch/nets/resnet/layers/__init__.py +17 -0
- wml/wtorch/nets/resnet/layers/aspp.py +144 -0
- wml/wtorch/nets/resnet/layers/batch_norm.py +231 -0
- wml/wtorch/nets/resnet/layers/blocks.py +111 -0
- wml/wtorch/nets/resnet/layers/wrappers.py +110 -0
- wml/wtorch/nets/resnet/r50_config.py +38 -0
- wml/wtorch/nets/resnet/resnet.py +691 -0
- wml/wtorch/nets/shape_spec.py +20 -0
- wml/wtorch/nets/simple_fpn.py +101 -0
- wml/wtorch/nms.py +109 -0
- wml/wtorch/nn.py +896 -0
- wml/wtorch/ocr_block.py +193 -0
- wml/wtorch/summary.py +331 -0
- wml/wtorch/train_toolkit.py +603 -0
- wml/wtorch/transformer_blocks.py +266 -0
- wml/wtorch/utils.py +719 -0
- wml/wtorch/wlr_scheduler.py +100 -0
|
@@ -0,0 +1,1953 @@
|
|
|
1
|
+
#coding=utf-8
|
|
2
|
+
import numpy as np
|
|
3
|
+
import os
|
|
4
|
+
import wml.object_detection2.npod_toolkit as npod
|
|
5
|
+
import wml.object_detection2.bboxes as odb
|
|
6
|
+
import math
|
|
7
|
+
import logging
|
|
8
|
+
from wml.thirdparty.odmetrics import coco_evaluation
|
|
9
|
+
from wml.thirdparty.odmetrics import standard_fields
|
|
10
|
+
import copy
|
|
11
|
+
import sys
|
|
12
|
+
from pycocotools.coco import COCO
|
|
13
|
+
from pycocotools.cocoeval import COCOeval
|
|
14
|
+
import wml.wml_utils as wmlu
|
|
15
|
+
from .build import METRICS_REGISTRY
|
|
16
|
+
from .classifier_toolkit import ConfusionMatrix
|
|
17
|
+
from .common import *
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def getF1(gtboxes,gtlabels,boxes,labels,threshold=0.5):
|
|
21
|
+
gt_shape = gtboxes.shape
|
|
22
|
+
#indict if there have some box match with this ground-truth box
|
|
23
|
+
gt_mask = np.zeros([gt_shape[0]],dtype=np.int32)
|
|
24
|
+
boxes_shape = boxes.shape
|
|
25
|
+
#indict if there have some ground-truth box match with this box
|
|
26
|
+
boxes_mask = np.zeros(boxes_shape[0],dtype=np.int32)
|
|
27
|
+
gt_size = gtlabels.shape[0]
|
|
28
|
+
boxes_size = labels.shape[0]
|
|
29
|
+
for i in range(gt_size):
|
|
30
|
+
max_index = -1
|
|
31
|
+
max_jaccard = 0.0
|
|
32
|
+
#iterator on all boxes to find one which have the most maximum jacard value with current ground-truth box
|
|
33
|
+
for j in range(boxes_size):
|
|
34
|
+
if gtlabels[i] != labels[j] or boxes_mask[j] != 0:
|
|
35
|
+
continue
|
|
36
|
+
jaccard = npod.box_jaccard(gtboxes[i],boxes[j])
|
|
37
|
+
if jaccard>threshold and jaccard > max_jaccard:
|
|
38
|
+
max_jaccard = jaccard
|
|
39
|
+
max_index = j
|
|
40
|
+
|
|
41
|
+
if max_index < 0:
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
gt_mask[i] = 1
|
|
45
|
+
boxes_mask[max_index] = 1
|
|
46
|
+
|
|
47
|
+
correct_num = np.sum(gt_mask)
|
|
48
|
+
f1 = safe_persent(2*correct_num,correct_num+gt_shape[0])
|
|
49
|
+
|
|
50
|
+
return f1
|
|
51
|
+
|
|
52
|
+
'''
|
|
53
|
+
gtboxes:[X,4](ymin,xmin,ymax,xmax) relative coordinates, ground truth boxes
|
|
54
|
+
gtlabels:[X] the labels for ground truth boxes
|
|
55
|
+
boxes:[Y,4](ymin,xmin,ymax,xmax) relative coordinates,predicted boxes
|
|
56
|
+
labels:[Y], the labels for predicted boxes
|
|
57
|
+
probability:[Y], the probability for boxes, if probability is none, assum the boxes's probability is ascending order
|
|
58
|
+
return:
|
|
59
|
+
mAP:[0,100]
|
|
60
|
+
'''
|
|
61
|
+
def getmAP(gtboxes,gtlabels,boxes,labels,probability=None,threshold=0.5,is_crowd=None):
|
|
62
|
+
|
|
63
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
64
|
+
gtboxes = np.array(gtboxes)
|
|
65
|
+
if len(gtboxes)==0:
|
|
66
|
+
gtboxes = np.zeros([0,4],dtype=np.float32)
|
|
67
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
68
|
+
gtlabels = np.array(gtlabels)
|
|
69
|
+
if len(gtlabels)==0:
|
|
70
|
+
gtlabels = np.zeros([0],dtype=np.int32)
|
|
71
|
+
if not isinstance(boxes,np.ndarray):
|
|
72
|
+
boxes = np.array(boxes)
|
|
73
|
+
if len(boxes)==0:
|
|
74
|
+
boxes = np.zeros([0,4],dtype=np.float32)
|
|
75
|
+
if not isinstance(labels,np.ndarray):
|
|
76
|
+
labels = np.array(labels)
|
|
77
|
+
if len(labels)==0:
|
|
78
|
+
labels = np.zeros([0],dtype=np.int32)
|
|
79
|
+
if is_crowd is None:
|
|
80
|
+
is_crowd = np.zeros([gtlabels.shape[0]],dtype=np.bool)
|
|
81
|
+
if len(is_crowd)==0:
|
|
82
|
+
is_crowd = np.zeros([0],dtype=np.bool)
|
|
83
|
+
if not isinstance(is_crowd,np.ndarray):
|
|
84
|
+
is_crowd = np.array(is_crowd)
|
|
85
|
+
|
|
86
|
+
gtboxes = copy.deepcopy(np.array(gtboxes))
|
|
87
|
+
gtlabels = copy.deepcopy(np.array(gtlabels))
|
|
88
|
+
boxes = copy.deepcopy(boxes)
|
|
89
|
+
labels = copy.deepcopy(labels)
|
|
90
|
+
if probability is not None:
|
|
91
|
+
probability = copy.deepcopy(probability)
|
|
92
|
+
index = np.argsort(probability)
|
|
93
|
+
boxes = boxes[index]
|
|
94
|
+
labels = labels[index]
|
|
95
|
+
|
|
96
|
+
max_nr = 20
|
|
97
|
+
data_nr = boxes.shape[0]
|
|
98
|
+
|
|
99
|
+
if data_nr==0:
|
|
100
|
+
if gtboxes.size == 0:
|
|
101
|
+
return 100.0
|
|
102
|
+
return 0.0
|
|
103
|
+
|
|
104
|
+
if data_nr>max_nr:
|
|
105
|
+
beg_index = range(0,data_nr,data_nr//max_nr)
|
|
106
|
+
else:
|
|
107
|
+
beg_index = range(0,data_nr)
|
|
108
|
+
|
|
109
|
+
t_res = []
|
|
110
|
+
|
|
111
|
+
for v in beg_index:
|
|
112
|
+
p,r = getPrecision(gtboxes,gtlabels,boxes[v:],labels[v:],threshold,is_crowd=is_crowd)
|
|
113
|
+
t_res.append([p,r])
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
t_res1 = []
|
|
117
|
+
old_v = None
|
|
118
|
+
for v in t_res:
|
|
119
|
+
if old_v is not None and v[0]<old_v[0]:
|
|
120
|
+
v[0] = old_v[0]
|
|
121
|
+
t_res1.append(v)
|
|
122
|
+
old_v = v
|
|
123
|
+
|
|
124
|
+
res = []
|
|
125
|
+
old_v = None
|
|
126
|
+
for v in reversed(t_res1):
|
|
127
|
+
if old_v is not None:
|
|
128
|
+
if v[1]<old_v[1]:
|
|
129
|
+
v[1] = old_v[1]
|
|
130
|
+
if math.fabs(v[1]-old_v[1])<1e-3 and v[0]<old_v[0]:
|
|
131
|
+
v[0] = old_v[0]
|
|
132
|
+
res.append(v)
|
|
133
|
+
old_v = v
|
|
134
|
+
|
|
135
|
+
min_r = res[0][1]
|
|
136
|
+
max_r = res[-1][1]
|
|
137
|
+
logging.debug("mAP: max r {}, min r {}".format(max_r,min_r))
|
|
138
|
+
|
|
139
|
+
if min_r > 1e-2:
|
|
140
|
+
res = np.concatenate([np.array([[res[0][0],0.]]),res],axis=0)
|
|
141
|
+
|
|
142
|
+
l_precisions = res[-1][0]
|
|
143
|
+
l_recall = res[-1][1]
|
|
144
|
+
append_res = []
|
|
145
|
+
cur_reall = l_recall
|
|
146
|
+
while cur_reall+10<100.0:
|
|
147
|
+
cur_reall = cur_reall+10
|
|
148
|
+
append_res.append([min(l_precisions,l_precisions*l_recall/cur_reall,l_recall),cur_reall])
|
|
149
|
+
|
|
150
|
+
if len(append_res)>0:
|
|
151
|
+
res = np.concatenate([res,np.array(append_res)],axis=0)
|
|
152
|
+
|
|
153
|
+
if max_r <100.0-1e-2:
|
|
154
|
+
l_precisions = res[-1][0]
|
|
155
|
+
l_recall = res[-1][1]
|
|
156
|
+
t_precision = min(l_precisions*l_recall/100.0,l_precisions,l_recall)
|
|
157
|
+
res = np.concatenate([res,np.array([[t_precision,100.0]])])
|
|
158
|
+
|
|
159
|
+
res = np.array(res)
|
|
160
|
+
res = res.transpose()
|
|
161
|
+
precisions = res[0]
|
|
162
|
+
recall = res[1]
|
|
163
|
+
new_r = np.arange(0.,100.01,10.).tolist()
|
|
164
|
+
new_p = []
|
|
165
|
+
for r in new_r:
|
|
166
|
+
new_p.append(np.interp(r,recall,precisions))
|
|
167
|
+
precisions = np.array(new_p)
|
|
168
|
+
return np.mean(precisions)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def getRecall(gtboxes,gtlabels,boxes,labels,threshold=0.5):
|
|
172
|
+
gt_shape = gtboxes.shape
|
|
173
|
+
#indict if there have some box match with this ground-truth box
|
|
174
|
+
gt_mask = np.zeros([gt_shape[0]],dtype=np.int32)
|
|
175
|
+
boxes_shape = boxes.shape
|
|
176
|
+
#indict if there have some ground-truth box match with this box
|
|
177
|
+
boxes_mask = np.zeros(boxes_shape[0],dtype=np.int32)
|
|
178
|
+
gt_size = gtlabels.shape[0]
|
|
179
|
+
boxes_size = labels.shape[0]
|
|
180
|
+
for i in range(gt_size):
|
|
181
|
+
max_index = -1
|
|
182
|
+
max_jaccard = 0.0
|
|
183
|
+
#iterator on all boxes to find one have the most maximum jacard value with current ground-truth box
|
|
184
|
+
for j in range(boxes_size):
|
|
185
|
+
if gtlabels[i] != labels[j] or boxes_mask[j] != 0:
|
|
186
|
+
continue
|
|
187
|
+
jaccard = npod.box_jaccard(gtboxes[i],boxes[j])
|
|
188
|
+
if jaccard>threshold and jaccard > max_jaccard:
|
|
189
|
+
max_jaccard = jaccard
|
|
190
|
+
max_index = j
|
|
191
|
+
|
|
192
|
+
if max_index < 0:
|
|
193
|
+
continue
|
|
194
|
+
|
|
195
|
+
gt_mask[i] = 1
|
|
196
|
+
boxes_mask[max_index] = 1
|
|
197
|
+
|
|
198
|
+
correct_num = np.sum(gt_mask)
|
|
199
|
+
total_num = gt_size
|
|
200
|
+
|
|
201
|
+
if 0 == total_num:
|
|
202
|
+
return 100.
|
|
203
|
+
|
|
204
|
+
return 100.*correct_num/total_num
|
|
205
|
+
|
|
206
|
+
def getAccuracy(gtboxes,gtlabels,boxes,labels,threshold=0.5,ext_info=False,is_crowd=None):
|
|
207
|
+
'''
|
|
208
|
+
:param gtboxes: [N,4]
|
|
209
|
+
:param gtlabels: [N]
|
|
210
|
+
:param boxes: [M,4]
|
|
211
|
+
:param labels: [M]
|
|
212
|
+
:param threshold: nms_threshold,float
|
|
213
|
+
:return: precision,recall float
|
|
214
|
+
'''
|
|
215
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
216
|
+
gtboxes = np.array(gtboxes)
|
|
217
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
218
|
+
gtlabels = np.array(gtlabels)
|
|
219
|
+
if is_crowd is None:
|
|
220
|
+
is_crowd = np.zeros([gtlabels.shape[0]],dtype=np.bool)
|
|
221
|
+
if not isinstance(is_crowd,np.ndarray):
|
|
222
|
+
is_crowd = np.array(is_crowd)
|
|
223
|
+
gt_shape = gtboxes.shape
|
|
224
|
+
#indict if there have some box match with this ground-truth box
|
|
225
|
+
gt_mask = np.zeros([gt_shape[0]],dtype=np.int32)
|
|
226
|
+
boxes_shape = boxes.shape
|
|
227
|
+
#indict if there have some ground-truth box match with this box
|
|
228
|
+
boxes_mask = np.zeros(boxes_shape[0],dtype=np.int32)
|
|
229
|
+
gt_size = gtlabels.shape[0]
|
|
230
|
+
boxes_size = labels.shape[0]
|
|
231
|
+
iou_matrix = odb.iou_matrix(gtboxes,boxes)
|
|
232
|
+
if iou_matrix.size>0:
|
|
233
|
+
target_idxs = np.argmax(iou_matrix,axis=-1)
|
|
234
|
+
else:
|
|
235
|
+
target_idxs = np.ones([gt_size])*-1
|
|
236
|
+
for i in range(gt_size):
|
|
237
|
+
max_index = -1
|
|
238
|
+
max_jaccard = 0.0
|
|
239
|
+
|
|
240
|
+
max_index = target_idxs[i]
|
|
241
|
+
if max_index<0:
|
|
242
|
+
continue
|
|
243
|
+
|
|
244
|
+
max_jaccard = iou_matrix[i,max_index]
|
|
245
|
+
if max_jaccard<threshold:
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
if gtlabels[i] == labels[max_index] and boxes_mask[max_index] == 0:
|
|
249
|
+
pass
|
|
250
|
+
else:
|
|
251
|
+
max_index = -1
|
|
252
|
+
for j in range(boxes_size):
|
|
253
|
+
if gtlabels[i] != labels[j] or boxes_mask[j] != 0:
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
jaccard = iou_matrix[i,j]
|
|
257
|
+
if jaccard>threshold and jaccard > max_jaccard:
|
|
258
|
+
max_jaccard = jaccard
|
|
259
|
+
max_index = j
|
|
260
|
+
|
|
261
|
+
if max_index < 0:
|
|
262
|
+
continue
|
|
263
|
+
|
|
264
|
+
gt_mask[i] = 1
|
|
265
|
+
boxes_mask[max_index] = 1
|
|
266
|
+
|
|
267
|
+
r_gt_mask = np.logical_or(gt_mask,is_crowd)
|
|
268
|
+
correct_gt_num = np.sum(r_gt_mask)
|
|
269
|
+
correct_bbox_num = np.sum(boxes_mask)
|
|
270
|
+
correct_num = np.sum(gt_mask)
|
|
271
|
+
r_gt_size = gt_size-correct_gt_num+correct_bbox_num
|
|
272
|
+
|
|
273
|
+
P_v = gt_size
|
|
274
|
+
TP_v = correct_bbox_num
|
|
275
|
+
FP_v = boxes_size-correct_num
|
|
276
|
+
|
|
277
|
+
return safe_persent(TP_v,r_gt_size+boxes_size-correct_bbox_num)
|
|
278
|
+
|
|
279
|
+
def getPrecision(gtboxes,gtlabels,boxes,labels,threshold=0.5,ext_info=False,is_crowd=None):
|
|
280
|
+
'''
|
|
281
|
+
:param gtboxes: [N,4]
|
|
282
|
+
:param gtlabels: [N]
|
|
283
|
+
:param boxes: [M,4]
|
|
284
|
+
:param labels: [M]
|
|
285
|
+
:param threshold: nms_threshold,float
|
|
286
|
+
:return: precision,recall float
|
|
287
|
+
'''
|
|
288
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
289
|
+
gtboxes = np.array(gtboxes)
|
|
290
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
291
|
+
gtlabels = np.array(gtlabels)
|
|
292
|
+
if not isinstance(labels,np.ndarray):
|
|
293
|
+
labels = np.array(labels)
|
|
294
|
+
if is_crowd is None:
|
|
295
|
+
is_crowd = np.zeros([gtlabels.shape[0]],dtype=np.bool)
|
|
296
|
+
if not isinstance(is_crowd,np.ndarray):
|
|
297
|
+
is_crowd = np.array(is_crowd)
|
|
298
|
+
gt_shape = gtboxes.shape
|
|
299
|
+
#indict if there have some box match with this ground-truth box
|
|
300
|
+
gt_mask = np.zeros([gt_shape[0]],dtype=np.int32)
|
|
301
|
+
boxes_shape = boxes.shape
|
|
302
|
+
#indict if there have some ground-truth box match with this box
|
|
303
|
+
boxes_mask = np.zeros(boxes_shape[0],dtype=np.int32)
|
|
304
|
+
gt_size = gtlabels.shape[0]
|
|
305
|
+
boxes_size = labels.shape[0]
|
|
306
|
+
iou_matrix = odb.iou_matrix(gtboxes,boxes)
|
|
307
|
+
if iou_matrix.size>0:
|
|
308
|
+
target_idxs = np.argmax(iou_matrix,axis=-1)
|
|
309
|
+
else:
|
|
310
|
+
target_idxs = np.ones([gt_size])*-1
|
|
311
|
+
#print(">>>>",gtboxes,gtlabels)
|
|
312
|
+
for i in range(gt_size):
|
|
313
|
+
max_index = -1
|
|
314
|
+
max_jaccard = 0.0
|
|
315
|
+
|
|
316
|
+
max_index = target_idxs[i]
|
|
317
|
+
if max_index<0:
|
|
318
|
+
continue
|
|
319
|
+
max_jaccard = iou_matrix[i,max_index]
|
|
320
|
+
if max_jaccard<threshold:
|
|
321
|
+
continue
|
|
322
|
+
|
|
323
|
+
if gtlabels[i] == labels[max_index] and boxes_mask[max_index] == 0:
|
|
324
|
+
pass
|
|
325
|
+
else:
|
|
326
|
+
max_index = -1
|
|
327
|
+
for j in range(boxes_size):
|
|
328
|
+
if gtlabels[i] != labels[j] or boxes_mask[j] != 0:
|
|
329
|
+
continue
|
|
330
|
+
|
|
331
|
+
jaccard = iou_matrix[i,j]
|
|
332
|
+
if jaccard>threshold and jaccard > max_jaccard:
|
|
333
|
+
max_jaccard = jaccard
|
|
334
|
+
max_index = j
|
|
335
|
+
|
|
336
|
+
if max_index < 0:
|
|
337
|
+
continue
|
|
338
|
+
|
|
339
|
+
gt_mask[i] = 1
|
|
340
|
+
boxes_mask[max_index] = 1
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
r_gt_mask = np.logical_or(gt_mask,is_crowd)
|
|
344
|
+
correct_gt_num = np.sum(r_gt_mask)
|
|
345
|
+
correct_bbox_num = np.sum(boxes_mask)
|
|
346
|
+
|
|
347
|
+
recall = safe_persent(correct_gt_num,gt_size)
|
|
348
|
+
precision = safe_persent(correct_bbox_num,boxes_size)
|
|
349
|
+
P_v = gt_size
|
|
350
|
+
TP_v = correct_bbox_num
|
|
351
|
+
FP_v = boxes_size-correct_bbox_num
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
if ext_info:
|
|
355
|
+
gt_label_list = []
|
|
356
|
+
for i in range(gt_mask.shape[0]):
|
|
357
|
+
if gt_mask[i] != 1:
|
|
358
|
+
gt_label_list.append(gtlabels[i])
|
|
359
|
+
pred_label_list = []
|
|
360
|
+
for i in range(boxes_size):
|
|
361
|
+
if boxes_mask[i] != 1:
|
|
362
|
+
pred_label_list.append(labels[i])
|
|
363
|
+
return precision,recall,gt_label_list,pred_label_list,TP_v,FP_v,P_v
|
|
364
|
+
else:
|
|
365
|
+
return precision,recall
|
|
366
|
+
|
|
367
|
+
def getEasyPrecision(gtboxes,gtlabels,boxes,labels,threshold=0.05,auto_scale_threshold=True,ext_info=False):
|
|
368
|
+
'''
|
|
369
|
+
:param gtboxes: [N,4]
|
|
370
|
+
:param gtlabels: [N]
|
|
371
|
+
:param boxes: [M,4]
|
|
372
|
+
:param labels: [M]
|
|
373
|
+
:param threshold: nms_threshold,float
|
|
374
|
+
:return: precision,recall float
|
|
375
|
+
'''
|
|
376
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
377
|
+
gtboxes = np.array(gtboxes)
|
|
378
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
379
|
+
gtlabels = np.array(gtlabels)
|
|
380
|
+
gt_shape = gtboxes.shape
|
|
381
|
+
#indict if there have some box match with this ground-truth box
|
|
382
|
+
gt_mask = np.zeros([gt_shape[0]],dtype=np.int32)
|
|
383
|
+
boxes_shape = boxes.shape
|
|
384
|
+
#indict if there have some ground-truth box match with this box
|
|
385
|
+
boxes_mask = np.zeros(boxes_shape[0],dtype=np.int32)
|
|
386
|
+
gt_size = gtlabels.shape[0]
|
|
387
|
+
boxes_size = labels.shape[0]
|
|
388
|
+
MIN_VOL = 0.005
|
|
389
|
+
#print(">>>>",gtboxes,gtlabels)
|
|
390
|
+
for i in range(gt_size):
|
|
391
|
+
max_index = -1
|
|
392
|
+
max_jaccard = 0.0
|
|
393
|
+
|
|
394
|
+
t_threshold = threshold
|
|
395
|
+
if auto_scale_threshold:
|
|
396
|
+
#print(i,gtboxes,gtlabels)
|
|
397
|
+
vol = npod.box_vol(gtboxes[i])
|
|
398
|
+
if vol < MIN_VOL:
|
|
399
|
+
t_threshold = vol*threshold/MIN_VOL
|
|
400
|
+
#iterator on all boxes to find one have the most maximum jacard value with current ground-truth box
|
|
401
|
+
for j in range(boxes_size):
|
|
402
|
+
if gtlabels[i] != labels[j] or boxes_mask[j] != 0:
|
|
403
|
+
continue
|
|
404
|
+
|
|
405
|
+
jaccard = npod.box_jaccard(gtboxes[i],boxes[j])
|
|
406
|
+
if jaccard>t_threshold and jaccard > max_jaccard:
|
|
407
|
+
max_jaccard = jaccard
|
|
408
|
+
max_index = j
|
|
409
|
+
|
|
410
|
+
if max_index < 0:
|
|
411
|
+
continue
|
|
412
|
+
|
|
413
|
+
gt_mask[i] = 1
|
|
414
|
+
boxes_mask[max_index] = 1
|
|
415
|
+
|
|
416
|
+
pred_labels = set(labels[boxes_mask.astype(np.bool)].tolist())
|
|
417
|
+
for j in range(boxes_size):
|
|
418
|
+
if boxes_mask[j] != 0:
|
|
419
|
+
continue
|
|
420
|
+
if labels[j] in pred_labels:
|
|
421
|
+
boxes_mask[j] = 1
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
correct_num = np.sum(gt_mask)
|
|
425
|
+
correct_num1 = np.sum(boxes_mask)
|
|
426
|
+
|
|
427
|
+
recall = safe_persent(correct_num,gt_size)
|
|
428
|
+
precision = safe_persent(correct_num1,boxes_size)
|
|
429
|
+
P_v = gt_size
|
|
430
|
+
TP_v = correct_num
|
|
431
|
+
FP_v = boxes_size-correct_num1
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
if ext_info:
|
|
435
|
+
gt_label_list = []
|
|
436
|
+
for i in range(gt_mask.shape[0]):
|
|
437
|
+
if gt_mask[i] != 1:
|
|
438
|
+
gt_label_list.append(gtlabels[i])
|
|
439
|
+
pred_label_list = []
|
|
440
|
+
for i in range(boxes_size):
|
|
441
|
+
if boxes_mask[i] != 1:
|
|
442
|
+
pred_label_list.append(labels[i])
|
|
443
|
+
return precision,recall,gt_label_list,pred_label_list,TP_v,FP_v,P_v
|
|
444
|
+
else:
|
|
445
|
+
return precision,recall
|
|
446
|
+
|
|
447
|
+
def getPrecisionV2(gt_data,pred_data,pred_func,threshold,return_f1=False):
|
|
448
|
+
'''
|
|
449
|
+
:param gt_data: N objects
|
|
450
|
+
:param pred_data: M object
|
|
451
|
+
:param pred_func: float (*)(obj0,obj1) get the distance of two objects, distance greater or equal zero
|
|
452
|
+
:return: precision,recall float
|
|
453
|
+
'''
|
|
454
|
+
NR_GT = len(gt_data)
|
|
455
|
+
NR_PRED = len(pred_data)
|
|
456
|
+
#indict if there have some box match with this ground-truth box
|
|
457
|
+
gt_mask = np.zeros([NR_GT],dtype=np.int32)
|
|
458
|
+
#indict if there have some ground-truth box match with this box
|
|
459
|
+
pred_mask = np.zeros(NR_PRED,dtype=np.int32)
|
|
460
|
+
for i in range(NR_GT):
|
|
461
|
+
min_index = -1
|
|
462
|
+
min_dis = 1e10
|
|
463
|
+
|
|
464
|
+
#iterator on all boxes to find one have the most maximum jacard value with current ground-truth box
|
|
465
|
+
for j in range(NR_PRED):
|
|
466
|
+
if pred_mask[j] != 0:
|
|
467
|
+
continue
|
|
468
|
+
dis = pred_func(gt_data[i],pred_data[j])
|
|
469
|
+
if dis<threshold and dis< min_dis:
|
|
470
|
+
min_dis = dis
|
|
471
|
+
min_index = j
|
|
472
|
+
|
|
473
|
+
if min_index < 0:
|
|
474
|
+
continue
|
|
475
|
+
|
|
476
|
+
gt_mask[i] = 1
|
|
477
|
+
pred_mask[min_index] = 1
|
|
478
|
+
|
|
479
|
+
correct_num = np.sum(gt_mask)
|
|
480
|
+
|
|
481
|
+
recall = safe_persent(correct_num,NR_GT)
|
|
482
|
+
precision = safe_persent(correct_num,NR_PRED)
|
|
483
|
+
|
|
484
|
+
if return_f1:
|
|
485
|
+
f1 = safe_persent(2*correct_num,NR_PRED+NR_GT)
|
|
486
|
+
return precision,recall,f1
|
|
487
|
+
|
|
488
|
+
return precision,recall
|
|
489
|
+
|
|
490
|
+
@METRICS_REGISTRY.register()
|
|
491
|
+
class Accuracy(BaseMetrics):
|
|
492
|
+
def __init__(self,threshold=0.1,num_classes=90,label_trans=None,classes_begin_value=1,*args,**kwargs):
|
|
493
|
+
super().__init__()
|
|
494
|
+
self.threshold = threshold
|
|
495
|
+
self.gtboxes = []
|
|
496
|
+
self.gtlabels = []
|
|
497
|
+
self.is_crowd = []
|
|
498
|
+
self.boxes = []
|
|
499
|
+
self.labels = []
|
|
500
|
+
self.precision = None
|
|
501
|
+
self.recall = None
|
|
502
|
+
self.total_test_nr = 0
|
|
503
|
+
self.num_classes = num_classes
|
|
504
|
+
self.label_trans = label_trans
|
|
505
|
+
self.bboxes_offset = np.zeros([1,4],dtype=np.float32)
|
|
506
|
+
del classes_begin_value
|
|
507
|
+
|
|
508
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
509
|
+
gtmasks=None,
|
|
510
|
+
masks=None,is_crowd=None,use_relative_coord=True):
|
|
511
|
+
if self.label_trans is not None:
|
|
512
|
+
gtlabels = self.label_trans(gtlabels)
|
|
513
|
+
labels = self.label_trans(labels)
|
|
514
|
+
if gtboxes.shape[0]>0:
|
|
515
|
+
self.gtboxes.append(np.array(gtboxes)+self.bboxes_offset)
|
|
516
|
+
self.gtlabels.append(np.array(gtlabels))
|
|
517
|
+
if is_crowd is None:
|
|
518
|
+
is_crowd = np.zeros([gtlabels.shape[0]],dtype=np.bool)
|
|
519
|
+
self.is_crowd.append(np.array(is_crowd))
|
|
520
|
+
if boxes.shape[0]>0:
|
|
521
|
+
self.boxes.append(np.array(boxes)+self.bboxes_offset)
|
|
522
|
+
self.labels.append(np.array(labels))
|
|
523
|
+
|
|
524
|
+
self.total_test_nr += 1
|
|
525
|
+
|
|
526
|
+
t_bboxes = np.concatenate([gtboxes,boxes],axis=0)
|
|
527
|
+
if t_bboxes.size>0:
|
|
528
|
+
t_max = np.max(t_bboxes,axis=0)
|
|
529
|
+
else:
|
|
530
|
+
t_max = np.zeros([4])
|
|
531
|
+
max_0 = t_max[2]
|
|
532
|
+
max_1 = t_max[3]
|
|
533
|
+
offset = np.array([[max_0,max_1,max_0,max_1]],dtype=np.float32)
|
|
534
|
+
self.bboxes_offset = self.bboxes_offset+offset
|
|
535
|
+
|
|
536
|
+
def evaluate(self):
|
|
537
|
+
if self.total_test_nr==0 or len(self.boxes)==0 or len(self.labels)==0:
|
|
538
|
+
self.precision,self.recall = 0,0
|
|
539
|
+
return
|
|
540
|
+
gtboxes = np.concatenate(self.gtboxes,axis=0)
|
|
541
|
+
gtlabels = np.concatenate(self.gtlabels,axis=0)
|
|
542
|
+
boxes = np.concatenate(self.boxes,axis=0)
|
|
543
|
+
labels = np.concatenate(self.labels,axis=0)
|
|
544
|
+
if self.is_crowd is not None and len(self.is_crowd)>0:
|
|
545
|
+
is_crowd = np.concatenate(self.is_crowd,axis=0)
|
|
546
|
+
else:
|
|
547
|
+
is_crowd = None
|
|
548
|
+
self.acc = getAccuracy(gtboxes, gtlabels, boxes, labels, threshold=self.threshold,
|
|
549
|
+
ext_info=False,
|
|
550
|
+
is_crowd=is_crowd)
|
|
551
|
+
def value(self):
|
|
552
|
+
return self.acc
|
|
553
|
+
|
|
554
|
+
def show(self,name=""):
|
|
555
|
+
self.evaluate()
|
|
556
|
+
res = f"{name}: total test nr {self.total_test_nr}, acc {self.acc:.3f}"
|
|
557
|
+
print(res)
|
|
558
|
+
|
|
559
|
+
def to_string(self):
|
|
560
|
+
try:
|
|
561
|
+
return f"{self.acc:.3f}({self.total_test_nr})"
|
|
562
|
+
except:
|
|
563
|
+
return "N.A."
|
|
564
|
+
|
|
565
|
+
@METRICS_REGISTRY.register()
|
|
566
|
+
class PrecisionAndRecall(BaseMetrics):
|
|
567
|
+
def __init__(self,threshold=0.5,num_classes=90,label_trans=None,classes_begin_value=1,*args,**kwargs):
|
|
568
|
+
self.threshold = threshold
|
|
569
|
+
self.gtboxes = []
|
|
570
|
+
self.gtlabels = []
|
|
571
|
+
self.boxes = []
|
|
572
|
+
self.labels = []
|
|
573
|
+
self.is_crowd = []
|
|
574
|
+
self.precision = None
|
|
575
|
+
self.recall = None
|
|
576
|
+
self.total_test_nr = 0
|
|
577
|
+
self.num_classes = num_classes
|
|
578
|
+
self.label_trans = label_trans
|
|
579
|
+
self.bboxes_offset = np.zeros([1,4],dtype=np.float32)
|
|
580
|
+
del classes_begin_value
|
|
581
|
+
|
|
582
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
583
|
+
gtmasks=None,
|
|
584
|
+
masks=None,is_crowd=None,use_relative_coord=True):
|
|
585
|
+
|
|
586
|
+
if self.label_trans is not None:
|
|
587
|
+
gtlabels = self.label_trans(gtlabels)
|
|
588
|
+
labels = self.label_trans(labels)
|
|
589
|
+
|
|
590
|
+
if gtboxes.shape[0]>0:
|
|
591
|
+
self.gtboxes.append(gtboxes+self.bboxes_offset)
|
|
592
|
+
self.gtlabels.append(np.array(gtlabels))
|
|
593
|
+
self.is_crowd.append(np.array(is_crowd))
|
|
594
|
+
|
|
595
|
+
if boxes.shape[0]>0:
|
|
596
|
+
self.boxes.append(boxes+self.bboxes_offset)
|
|
597
|
+
self.labels.append(np.array(labels))
|
|
598
|
+
if len(gtboxes)==0:
|
|
599
|
+
gtboxes = np.zeros([0,4],dtype=gtboxes.dtype)
|
|
600
|
+
|
|
601
|
+
if boxes.size == 0:
|
|
602
|
+
boxes = np.zeros([0,4],dtype=boxes.dtype)
|
|
603
|
+
|
|
604
|
+
t_bboxes = np.concatenate([gtboxes,boxes],axis=0)
|
|
605
|
+
if len(t_bboxes)>0:
|
|
606
|
+
t_max = np.max(t_bboxes,axis=0)
|
|
607
|
+
else:
|
|
608
|
+
t_max = [0,0,0,0]
|
|
609
|
+
max_0 = t_max[2]
|
|
610
|
+
max_1 = t_max[3]
|
|
611
|
+
offset = np.array([[max_0,max_1,max_0,max_1]],dtype=np.float32)
|
|
612
|
+
self.bboxes_offset = self.bboxes_offset+offset
|
|
613
|
+
|
|
614
|
+
self.total_test_nr += 1
|
|
615
|
+
|
|
616
|
+
cur_precision,cur_recall = getPrecision(gtboxes=gtboxes,
|
|
617
|
+
gtlabels=gtlabels,
|
|
618
|
+
boxes=boxes,labels=labels,
|
|
619
|
+
threshold=self.threshold,
|
|
620
|
+
ext_info=False,
|
|
621
|
+
is_crowd=is_crowd)
|
|
622
|
+
self._current_info = f"precision={cur_precision:.3f}, recall={cur_recall:.3f}"
|
|
623
|
+
|
|
624
|
+
def evaluate(self):
|
|
625
|
+
if self.total_test_nr==0 or len(self.boxes)==0 or len(self.labels)==0:
|
|
626
|
+
self.precision,self.recall = 0,0
|
|
627
|
+
return
|
|
628
|
+
if len(self.gtboxes) == 0:
|
|
629
|
+
gtboxes = np.zeros([0,4],dtype=np.float32)
|
|
630
|
+
gtlabels = np.zeros([0],dtype=np.int32)
|
|
631
|
+
is_crowd = np.zeros([0],dtype=np.bool)
|
|
632
|
+
else:
|
|
633
|
+
gtboxes = np.concatenate(self.gtboxes,axis=0)
|
|
634
|
+
gtlabels = np.concatenate(self.gtlabels,axis=0)
|
|
635
|
+
is_crowd = np.concatenate(self.is_crowd,axis=0).astype(np.bool)
|
|
636
|
+
boxes = np.concatenate(self.boxes,axis=0)
|
|
637
|
+
labels = np.concatenate(self.labels,axis=0)
|
|
638
|
+
self.precision,self.recall = getPrecision(gtboxes, gtlabels, boxes, labels, threshold=self.threshold,
|
|
639
|
+
ext_info=False,
|
|
640
|
+
is_crowd=is_crowd)
|
|
641
|
+
@property
|
|
642
|
+
def f1(self):
|
|
643
|
+
return 2*self.precision*self.recall/max(self.precision+self.recall,1e-8)
|
|
644
|
+
|
|
645
|
+
def show(self,name=""):
|
|
646
|
+
self.evaluate()
|
|
647
|
+
res = f"{name}: {self}"
|
|
648
|
+
print(res)
|
|
649
|
+
|
|
650
|
+
def value(self):
|
|
651
|
+
return self.f1
|
|
652
|
+
|
|
653
|
+
def detail_valus(self):
|
|
654
|
+
return self.precision,self.recall
|
|
655
|
+
|
|
656
|
+
def to_string(self):
|
|
657
|
+
try:
|
|
658
|
+
return f"{self.precision:.3f}/{self.recall:.3f}/{self.f1:.3f}/({self.total_test_nr})"
|
|
659
|
+
except:
|
|
660
|
+
return "N.A."
|
|
661
|
+
|
|
662
|
+
def __repr__(self):
|
|
663
|
+
res = f"total test nr {self.total_test_nr}, precision {self.precision:.3f}, recall {self.recall:.3f}, f1 {self.f1:.3f}"
|
|
664
|
+
return res
|
|
665
|
+
|
|
666
|
+
@METRICS_REGISTRY.register()
|
|
667
|
+
class EasyPrecisionAndRecall(BaseMetrics):
|
|
668
|
+
def __init__(self,threshold=0.05,num_classes=90,label_trans=None,classes_begin_value=1,*args,**kwargs):
|
|
669
|
+
self.threshold = threshold
|
|
670
|
+
self.gtboxes = []
|
|
671
|
+
self.gtlabels = []
|
|
672
|
+
self.boxes = []
|
|
673
|
+
self.labels = []
|
|
674
|
+
self.precision = None
|
|
675
|
+
self.recall = None
|
|
676
|
+
self.total_test_nr = 0
|
|
677
|
+
self.num_classes = num_classes
|
|
678
|
+
self.label_trans = label_trans
|
|
679
|
+
del classes_begin_value
|
|
680
|
+
|
|
681
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
682
|
+
gtmasks=None,
|
|
683
|
+
masks=None,is_crowd=None,use_relative_coord=True):
|
|
684
|
+
if self.label_trans is not None:
|
|
685
|
+
gtlabels = self.label_trans(gtlabels)
|
|
686
|
+
labels = self.label_trans(labels)
|
|
687
|
+
if gtboxes.shape[0]>0:
|
|
688
|
+
self.gtboxes.append(gtboxes)
|
|
689
|
+
self.gtlabels.append(np.array(gtlabels)+self.total_test_nr*self.num_classes)
|
|
690
|
+
if boxes.shape[0]>0:
|
|
691
|
+
self.boxes.append(boxes)
|
|
692
|
+
self.labels.append(np.array(labels)+self.total_test_nr*self.num_classes)
|
|
693
|
+
self.total_test_nr += 1
|
|
694
|
+
|
|
695
|
+
def evaluate(self):
|
|
696
|
+
if self.total_test_nr==0 or len(self.boxes)==0 or len(self.labels)==0:
|
|
697
|
+
self.precision,self.recall = 0,0
|
|
698
|
+
return
|
|
699
|
+
gtboxes = np.concatenate(self.gtboxes,axis=0)
|
|
700
|
+
gtlabels = np.concatenate(self.gtlabels,axis=0)
|
|
701
|
+
boxes = np.concatenate(self.boxes,axis=0)
|
|
702
|
+
labels = np.concatenate(self.labels,axis=0)
|
|
703
|
+
self.precision,self.recall = getEasyPrecision(gtboxes, gtlabels, boxes, labels, threshold=self.threshold,
|
|
704
|
+
auto_scale_threshold=False, ext_info=False)
|
|
705
|
+
@property
|
|
706
|
+
def f1(self):
|
|
707
|
+
return 2*self.precision*self.recall/max(self.precision+self.recall,1e-8)
|
|
708
|
+
|
|
709
|
+
def show(self,name=""):
|
|
710
|
+
self.evaluate()
|
|
711
|
+
res = f"{name}: {self}"
|
|
712
|
+
print(res)
|
|
713
|
+
|
|
714
|
+
def value(self):
|
|
715
|
+
return self.f1
|
|
716
|
+
|
|
717
|
+
def detail_valus(self):
|
|
718
|
+
return self.precision,self.recall
|
|
719
|
+
|
|
720
|
+
def to_string(self):
|
|
721
|
+
try:
|
|
722
|
+
return f"{self.precision:.3f}/{self.recall:.3f}/{self.f1}/({self.total_test_nr})"
|
|
723
|
+
except:
|
|
724
|
+
return "N.A."
|
|
725
|
+
|
|
726
|
+
def __repr__(self):
|
|
727
|
+
res = f"total test nr {self.total_test_nr}, precision {self.precision:.3f}, recall {self.recall:.3f}, f1 {self.f1}"
|
|
728
|
+
return res
|
|
729
|
+
|
|
730
|
+
@METRICS_REGISTRY.register()
|
|
731
|
+
class ClsPrecisionAndRecall(BaseMetrics):
|
|
732
|
+
def __init__(self,threshold=0.5,num_classes=90,label_trans=None,classes_begin_value=1,*args,**kwargs):
|
|
733
|
+
self.threshold = threshold
|
|
734
|
+
self.precision = None
|
|
735
|
+
self.recall = None
|
|
736
|
+
self.total_test_nr = 0
|
|
737
|
+
self.num_classes = num_classes
|
|
738
|
+
self.label_trans = label_trans
|
|
739
|
+
del classes_begin_value
|
|
740
|
+
self.tp = 0
|
|
741
|
+
self.fn = 0
|
|
742
|
+
self.fp = 0
|
|
743
|
+
|
|
744
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
745
|
+
gtmasks=None,
|
|
746
|
+
masks=None,is_crowd=None,use_relative_coord=True):
|
|
747
|
+
if self.label_trans is not None:
|
|
748
|
+
gtlabels = self.label_trans(gtlabels)
|
|
749
|
+
labels = self.label_trans(labels)
|
|
750
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
751
|
+
gtlabels = np.array(gtlabels)
|
|
752
|
+
if is_crowd is not None and not isinstance(is_crowd,np.ndarray):
|
|
753
|
+
is_crowd = np.array(is_crowd)
|
|
754
|
+
ori_gtlabels = gtlabels.copy()
|
|
755
|
+
gtlabels = set(gtlabels)
|
|
756
|
+
labels = set(labels)
|
|
757
|
+
union_labels = gtlabels&labels
|
|
758
|
+
tp = len(union_labels)
|
|
759
|
+
false_negative = gtlabels-union_labels
|
|
760
|
+
fn = len(false_negative)
|
|
761
|
+
|
|
762
|
+
if is_crowd is not None:
|
|
763
|
+
for l in false_negative:
|
|
764
|
+
mask = ori_gtlabels==l
|
|
765
|
+
t_is_crowd = is_crowd[mask]
|
|
766
|
+
if np.all(t_is_crowd):
|
|
767
|
+
fn = fn-1
|
|
768
|
+
|
|
769
|
+
fp = len(labels)-tp
|
|
770
|
+
self.tp += tp
|
|
771
|
+
self.fn += fn
|
|
772
|
+
self.fp += fp
|
|
773
|
+
self.total_test_nr += 1
|
|
774
|
+
if fp+tp>0:
|
|
775
|
+
precision = tp/(fp+tp)
|
|
776
|
+
else:
|
|
777
|
+
precision = 1.0
|
|
778
|
+
if fn+tp>0:
|
|
779
|
+
recall = tp/(fn+tp)
|
|
780
|
+
else:
|
|
781
|
+
recall = 1.0
|
|
782
|
+
self._current_info = f"precision={precision:.3f}, recall={recall:.3f}"
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
def evaluate(self):
|
|
787
|
+
if self.total_test_nr==0:
|
|
788
|
+
self.precision,self.recall = 0,0
|
|
789
|
+
return
|
|
790
|
+
self.precision = self.tp/max(self.fp+self.tp,1)
|
|
791
|
+
self.recall = self.tp/max(self.fn+self.tp,1)
|
|
792
|
+
|
|
793
|
+
@property
|
|
794
|
+
def f1(self):
|
|
795
|
+
return 2*self.precision*self.recall/max(self.precision+self.recall,1e-8)
|
|
796
|
+
|
|
797
|
+
def show(self,name=""):
|
|
798
|
+
self.evaluate()
|
|
799
|
+
res = f"{name}: {self}"
|
|
800
|
+
print(res)
|
|
801
|
+
|
|
802
|
+
def value(self):
|
|
803
|
+
return self.f1
|
|
804
|
+
|
|
805
|
+
def detail_valus(self):
|
|
806
|
+
return self.precision,self.recall
|
|
807
|
+
|
|
808
|
+
def to_string(self):
|
|
809
|
+
try:
|
|
810
|
+
return f"{self.precision:.3f}/{self.recall:.3f}/{self.f1}/({self.total_test_nr})"
|
|
811
|
+
except:
|
|
812
|
+
return "N.A."
|
|
813
|
+
|
|
814
|
+
def __repr__(self):
|
|
815
|
+
res = f"total test nr {self.total_test_nr}, precision {self.precision:.3f}, recall {self.recall:.3f}, f1 {self.f1}"
|
|
816
|
+
return res
|
|
817
|
+
|
|
818
|
+
@METRICS_REGISTRY.register()
|
|
819
|
+
class ROC:
|
|
820
|
+
def __init__(self,threshold=0.5,num_classes=90,label_trans=None,classes_begin_value=1,*args,**kwargs):
|
|
821
|
+
self.threshold = threshold
|
|
822
|
+
self.gtboxes = []
|
|
823
|
+
self.gtlabels = []
|
|
824
|
+
self.boxes = []
|
|
825
|
+
self.labels = []
|
|
826
|
+
self.probs = []
|
|
827
|
+
self.precision = None
|
|
828
|
+
self.recall = None
|
|
829
|
+
self.total_test_nr = 0
|
|
830
|
+
self.num_classes = num_classes
|
|
831
|
+
self.label_trans = label_trans
|
|
832
|
+
self.results = None
|
|
833
|
+
del classes_begin_value
|
|
834
|
+
|
|
835
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
836
|
+
gtmasks=None,
|
|
837
|
+
masks=None,is_crowd=None):
|
|
838
|
+
if self.label_trans is not None:
|
|
839
|
+
gtlabels = self.label_trans(gtlabels)
|
|
840
|
+
labels = self.label_trans(labels)
|
|
841
|
+
if gtboxes.shape[0]>0:
|
|
842
|
+
self.gtboxes.append(gtboxes)
|
|
843
|
+
self.gtlabels.append(np.array(gtlabels)+self.total_test_nr*self.num_classes)
|
|
844
|
+
if boxes.shape[0]>0:
|
|
845
|
+
self.boxes.append(boxes)
|
|
846
|
+
self.labels.append(np.array(labels)+self.total_test_nr*self.num_classes)
|
|
847
|
+
self.probs.append(np.array(probability))
|
|
848
|
+
self.total_test_nr += 1
|
|
849
|
+
|
|
850
|
+
def evaluate(self):
|
|
851
|
+
if self.total_test_nr==0 or len(self.boxes)==0 or len(self.labels)==0:
|
|
852
|
+
self.precision,self.recall = 0,0
|
|
853
|
+
return
|
|
854
|
+
gtboxes = np.concatenate(self.gtboxes,axis=0)
|
|
855
|
+
gtlabels = np.concatenate(self.gtlabels,axis=0)
|
|
856
|
+
boxes = np.concatenate(self.boxes,axis=0)
|
|
857
|
+
labels = np.concatenate(self.labels,axis=0)
|
|
858
|
+
probs = np.concatenate(self.probs,axis=0)
|
|
859
|
+
self.results = []
|
|
860
|
+
|
|
861
|
+
for p in np.arange(0,1,0.05):
|
|
862
|
+
mask = np.greater(probs,p)
|
|
863
|
+
t_boxes = boxes[mask]
|
|
864
|
+
t_labels = labels[mask]
|
|
865
|
+
precision, recall, gt_label_list, pred_label_list, TP_v, FP_v, P_v = \
|
|
866
|
+
getPrecision(gtboxes, gtlabels, t_boxes, t_labels, threshold=self.threshold,
|
|
867
|
+
ext_info=True)
|
|
868
|
+
self.results.append([p,precision,recall])
|
|
869
|
+
|
|
870
|
+
def show(self,name=""):
|
|
871
|
+
print(self.to_string())
|
|
872
|
+
|
|
873
|
+
def to_string(self):
|
|
874
|
+
self.evaluate()
|
|
875
|
+
res = ""
|
|
876
|
+
if self.results is None or len(self.results) == 0:
|
|
877
|
+
return res
|
|
878
|
+
for p, precision, recall in self.results:
|
|
879
|
+
res += f"{p:.3f},{precision:.3f},{recall:.3f};\n"
|
|
880
|
+
|
|
881
|
+
return res
|
|
882
|
+
|
|
883
|
+
class ModelPerformance:
|
|
884
|
+
def __init__(self,threshold,no_mAP=False,no_F1=False):
|
|
885
|
+
self.total_map = 0.
|
|
886
|
+
self.total_recall = 0.
|
|
887
|
+
self.total_precision = 0.
|
|
888
|
+
self.total_F1 = 0.
|
|
889
|
+
self.threshold = threshold
|
|
890
|
+
self.test_nr = 0
|
|
891
|
+
self.no_mAP=no_mAP
|
|
892
|
+
self.no_F1 = no_F1
|
|
893
|
+
|
|
894
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None):
|
|
895
|
+
gtboxes = copy.deepcopy(np.array(gtboxes))
|
|
896
|
+
gtlabels = copy.deepcopy(np.array(gtlabels))
|
|
897
|
+
boxes = copy.deepcopy(boxes)
|
|
898
|
+
labels = copy.deepcopy(labels)
|
|
899
|
+
if probability is not None:
|
|
900
|
+
probability = copy.deepcopy(probability)
|
|
901
|
+
|
|
902
|
+
if self.no_mAP:
|
|
903
|
+
ap = 0.
|
|
904
|
+
else:
|
|
905
|
+
ap = getmAP(gtboxes, gtlabels, boxes, labels, probability=probability,threshold=self.threshold)
|
|
906
|
+
|
|
907
|
+
rc = getRecall(gtboxes, gtlabels, boxes, labels, self.threshold)
|
|
908
|
+
|
|
909
|
+
if self.no_F1:
|
|
910
|
+
f1 = 0.
|
|
911
|
+
else:
|
|
912
|
+
f1 = getF1(gtboxes, gtlabels, boxes, labels, self.threshold)
|
|
913
|
+
|
|
914
|
+
pc,_ = getPrecision(gtboxes, gtlabels, boxes, labels, self.threshold)
|
|
915
|
+
|
|
916
|
+
self.total_map += ap
|
|
917
|
+
self.total_recall += rc
|
|
918
|
+
self.total_precision += pc
|
|
919
|
+
self.total_F1 += f1
|
|
920
|
+
self.test_nr += 1
|
|
921
|
+
return ap,rc,pc,f1
|
|
922
|
+
|
|
923
|
+
@staticmethod
|
|
924
|
+
def safe_div(v0,v1):
|
|
925
|
+
if math.fabs(v1)<1e-8:
|
|
926
|
+
return 0.
|
|
927
|
+
return v0/v1
|
|
928
|
+
|
|
929
|
+
def __getattr__(self, item):
|
|
930
|
+
if item=="mAP":
|
|
931
|
+
return self.safe_div(self.total_map,self.test_nr)
|
|
932
|
+
elif item =="recall":
|
|
933
|
+
return self.safe_div(self.total_recall,self.test_nr)
|
|
934
|
+
elif item=="precision":
|
|
935
|
+
return self.safe_div(self.total_precision,self.test_nr)
|
|
936
|
+
|
|
937
|
+
class GeneralCOCOEvaluation(BaseMetrics):
|
|
938
|
+
def __init__(self,categories_list=None,
|
|
939
|
+
num_classes=None,mask_on=False,label_trans=None,
|
|
940
|
+
classes_begin_value=1,
|
|
941
|
+
min_bbox_size=0,
|
|
942
|
+
one_classes=False,
|
|
943
|
+
**kwargs):
|
|
944
|
+
super().__init__(**kwargs)
|
|
945
|
+
if categories_list is None:
|
|
946
|
+
print(f"WARNING: Use default categories list, start classes is {classes_begin_value}")
|
|
947
|
+
self.categories_list = [{"id":x+classes_begin_value,"name":str(x+classes_begin_value)} for x in range(num_classes)]
|
|
948
|
+
else:
|
|
949
|
+
self.categories_list = categories_list
|
|
950
|
+
if not mask_on:
|
|
951
|
+
self.coco_evaluator = coco_evaluation.CocoDetectionEvaluator(
|
|
952
|
+
self.categories_list,include_metrics_per_category=False)
|
|
953
|
+
else:
|
|
954
|
+
self.coco_evaluator = coco_evaluation.CocoMaskEvaluator(
|
|
955
|
+
self.categories_list,include_metrics_per_category=False)
|
|
956
|
+
self.min_bbox_size = min_bbox_size
|
|
957
|
+
if self.min_bbox_size > 0:
|
|
958
|
+
print(f"{type(self).__name__}: set min_bbox_size to {self.min_bbox_size}")
|
|
959
|
+
self.label_trans = label_trans
|
|
960
|
+
self.image_id = 0
|
|
961
|
+
self.cached_values = {}
|
|
962
|
+
self.one_classes = one_classes
|
|
963
|
+
'''
|
|
964
|
+
gtboxes:[N,4]
|
|
965
|
+
gtlabels:[N]
|
|
966
|
+
img_size:[H,W]
|
|
967
|
+
gtmasks:[N,H,W]
|
|
968
|
+
is_crowd: [N]
|
|
969
|
+
'''
|
|
970
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
971
|
+
gtmasks=None,
|
|
972
|
+
masks=None,is_crowd=None,use_relative_coord=False):
|
|
973
|
+
if self.min_bbox_size > 0:
|
|
974
|
+
gtboxes = odb.clamp_bboxes(gtboxes,self.min_bbox_size)
|
|
975
|
+
boxes = odb.clamp_bboxes(boxes,self.min_bbox_size)
|
|
976
|
+
|
|
977
|
+
cur_ap = getmAP(gtboxes=gtboxes,
|
|
978
|
+
gtlabels=gtlabels,
|
|
979
|
+
boxes=boxes,
|
|
980
|
+
labels=labels,
|
|
981
|
+
probability=probability,
|
|
982
|
+
is_crowd=is_crowd)
|
|
983
|
+
self._current_info = f"ap={cur_ap:.3f}"
|
|
984
|
+
|
|
985
|
+
if probability is None:
|
|
986
|
+
probability = np.ones_like(labels,dtype=np.float32)
|
|
987
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
988
|
+
gtboxes = np.array(gtboxes)
|
|
989
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
990
|
+
gtlabels = np.array(gtlabels)
|
|
991
|
+
if not isinstance(boxes,np.ndarray):
|
|
992
|
+
boxes = np.array(boxes)
|
|
993
|
+
if not isinstance(labels,np.ndarray):
|
|
994
|
+
labels = np.array(labels)
|
|
995
|
+
if self.label_trans is not None:
|
|
996
|
+
gtlabels = self.label_trans(gtlabels)
|
|
997
|
+
labels = self.label_trans(labels)
|
|
998
|
+
|
|
999
|
+
if self.one_classes:
|
|
1000
|
+
gtlabels = np.zeros_like(gtlabels)
|
|
1001
|
+
labels = np.zeros_like(labels)
|
|
1002
|
+
|
|
1003
|
+
if probability is not None and not isinstance(probability,np.ndarray):
|
|
1004
|
+
probability = np.array(probability)
|
|
1005
|
+
if gtlabels.shape[0]>0:
|
|
1006
|
+
if use_relative_coord:
|
|
1007
|
+
gtboxes = gtboxes*[[img_size[0],img_size[1],img_size[0],img_size[1]]]
|
|
1008
|
+
groundtruth_dict={
|
|
1009
|
+
standard_fields.InputDataFields.groundtruth_boxes:
|
|
1010
|
+
gtboxes,
|
|
1011
|
+
standard_fields.InputDataFields.groundtruth_classes:gtlabels,
|
|
1012
|
+
}
|
|
1013
|
+
if is_crowd is not None:
|
|
1014
|
+
if not isinstance(is_crowd,np.ndarray):
|
|
1015
|
+
is_crowd = np.array(is_crowd)
|
|
1016
|
+
groundtruth_dict[standard_fields.InputDataFields.groundtruth_is_crowd] = is_crowd
|
|
1017
|
+
if gtmasks is not None:
|
|
1018
|
+
groundtruth_dict[standard_fields.InputDataFields.groundtruth_instance_masks] = gtmasks
|
|
1019
|
+
self.coco_evaluator.add_single_ground_truth_image_info(
|
|
1020
|
+
image_id=str(self.image_id),
|
|
1021
|
+
groundtruth_dict=groundtruth_dict)
|
|
1022
|
+
if labels.shape[0]>0 and gtlabels.shape[0]>0:
|
|
1023
|
+
if use_relative_coord:
|
|
1024
|
+
boxes = boxes*[[img_size[0],img_size[1],img_size[0],img_size[1]]]
|
|
1025
|
+
detections_dict={
|
|
1026
|
+
standard_fields.DetectionResultFields.detection_boxes:
|
|
1027
|
+
boxes,
|
|
1028
|
+
standard_fields.DetectionResultFields.detection_scores:
|
|
1029
|
+
probability,
|
|
1030
|
+
standard_fields.DetectionResultFields.detection_classes:
|
|
1031
|
+
labels
|
|
1032
|
+
}
|
|
1033
|
+
if masks is not None:
|
|
1034
|
+
detections_dict[standard_fields.DetectionResultFields.detection_masks] = masks
|
|
1035
|
+
self.coco_evaluator.add_single_detected_image_info(
|
|
1036
|
+
image_id=str(self.image_id),
|
|
1037
|
+
detections_dict=detections_dict)
|
|
1038
|
+
self.image_id += 1
|
|
1039
|
+
|
|
1040
|
+
def num_examples(self):
|
|
1041
|
+
if '_image_ids_with_detections' in self.coco_evaluator.__dict__:
|
|
1042
|
+
return len(self.coco_evaluator._image_ids_with_detections)
|
|
1043
|
+
elif '_image_ids' in self.coco_evaluator.__dict__:
|
|
1044
|
+
return len(self.coco_evaluator._image_ids)
|
|
1045
|
+
else:
|
|
1046
|
+
raise RuntimeError("Error evaluator type.")
|
|
1047
|
+
|
|
1048
|
+
def evaluate(self):
|
|
1049
|
+
print(f"Test size {self.num_examples()}")
|
|
1050
|
+
res = self.coco_evaluator.evaluate()
|
|
1051
|
+
for k,v in res.items():
|
|
1052
|
+
index = k.find("/")
|
|
1053
|
+
if index>0:
|
|
1054
|
+
k = k[index+1:]
|
|
1055
|
+
self.cached_values[k] = v
|
|
1056
|
+
|
|
1057
|
+
return res
|
|
1058
|
+
|
|
1059
|
+
def show(self,name=""):
|
|
1060
|
+
sys.stdout.flush()
|
|
1061
|
+
|
|
1062
|
+
if name is None or len(name)==0:
|
|
1063
|
+
name = self.cfg_name
|
|
1064
|
+
|
|
1065
|
+
print(f"Test size {self.num_examples()}")
|
|
1066
|
+
res = self.coco_evaluator.evaluate()
|
|
1067
|
+
str0 = "|配置|"
|
|
1068
|
+
str1 = "|---|"
|
|
1069
|
+
str2 = f"|{name}|"
|
|
1070
|
+
for k,v in res.items():
|
|
1071
|
+
index = k.find("/")
|
|
1072
|
+
if index>0:
|
|
1073
|
+
k = k[index+1:]
|
|
1074
|
+
self.cached_values[k] = v
|
|
1075
|
+
str0 += f"{k}|"
|
|
1076
|
+
str1 += "---|"
|
|
1077
|
+
str2 += f"{v:.3f}|"
|
|
1078
|
+
print(str0)
|
|
1079
|
+
print(str1)
|
|
1080
|
+
print(str2)
|
|
1081
|
+
sys.stdout.flush()
|
|
1082
|
+
return res
|
|
1083
|
+
|
|
1084
|
+
def to_string(self):
|
|
1085
|
+
if 'mAP' in self.cached_values and 'mAP@.50IOU' in self.cached_values:
|
|
1086
|
+
#return f"{self.cached_values['mAP@.50IOU']:.3f}/{self.cached_values['mAP']:.3f}"
|
|
1087
|
+
return f"{self.cached_values['mAP@.50IOU']:.3f}"
|
|
1088
|
+
else:
|
|
1089
|
+
return f"N.A."
|
|
1090
|
+
|
|
1091
|
+
def __repr__(self):
|
|
1092
|
+
return self.to_string()
|
|
1093
|
+
|
|
1094
|
+
def value(self):
|
|
1095
|
+
if 'mAP' in self.cached_values:
|
|
1096
|
+
return self.cached_values['mAP']
|
|
1097
|
+
elif 'mAP@.50IOU' in self.cached_values:
|
|
1098
|
+
return self.cached_values['mAP@.50IOU']
|
|
1099
|
+
else:
|
|
1100
|
+
return 0.0
|
|
1101
|
+
|
|
1102
|
+
@METRICS_REGISTRY.register()
|
|
1103
|
+
class COCOBoxEvaluation(GeneralCOCOEvaluation):
|
|
1104
|
+
def __init__(self,categories_list=None,num_classes=None,label_trans=None,classes_begin_value=1,**kwargs):
|
|
1105
|
+
super().__init__(categories_list=categories_list,
|
|
1106
|
+
num_classes=num_classes,
|
|
1107
|
+
mask_on=False,
|
|
1108
|
+
label_trans=label_trans,
|
|
1109
|
+
classes_begin_value=classes_begin_value,
|
|
1110
|
+
**kwargs)
|
|
1111
|
+
@METRICS_REGISTRY.register()
|
|
1112
|
+
class COCOMaskEvaluation(GeneralCOCOEvaluation):
|
|
1113
|
+
def __init__(self,categories_list=None,num_classes=None,label_trans=None,classes_begin_value=1,**kwargs):
|
|
1114
|
+
super().__init__(categories_list=categories_list,
|
|
1115
|
+
num_classes=num_classes,
|
|
1116
|
+
mask_on=True,
|
|
1117
|
+
label_trans=label_trans,
|
|
1118
|
+
classes_begin_value=classes_begin_value,
|
|
1119
|
+
**kwargs)
|
|
1120
|
+
|
|
1121
|
+
@METRICS_REGISTRY.register()
|
|
1122
|
+
class COCOEvaluation(BaseMetrics):
|
|
1123
|
+
'''
|
|
1124
|
+
num_classes: 不包含背景
|
|
1125
|
+
'''
|
|
1126
|
+
def __init__(self,categories_list=None,num_classes=None,mask_on=False,label_trans=None,classes_begin_value=1,**kwargs):
|
|
1127
|
+
super().__init__(**kwargs)
|
|
1128
|
+
self.box_evaluator = COCOBoxEvaluation(categories_list=categories_list,
|
|
1129
|
+
num_classes=num_classes,
|
|
1130
|
+
label_trans=label_trans,
|
|
1131
|
+
classes_begin_value=classes_begin_value,
|
|
1132
|
+
**kwargs)
|
|
1133
|
+
self.mask_evaluator = None
|
|
1134
|
+
if mask_on:
|
|
1135
|
+
self.mask_evaluator = COCOMaskEvaluation(categories_list=categories_list,
|
|
1136
|
+
num_classes=num_classes,
|
|
1137
|
+
label_trans=label_trans,
|
|
1138
|
+
classes_begin_value=classes_begin_value,
|
|
1139
|
+
**kwargs)
|
|
1140
|
+
def __call__(self, *args, **kwargs):
|
|
1141
|
+
self.box_evaluator(*args,**kwargs)
|
|
1142
|
+
self._current_info = self.box_evaluator.current_info()
|
|
1143
|
+
if self.mask_evaluator is not None:
|
|
1144
|
+
self.mask_evaluator(*args,**kwargs)
|
|
1145
|
+
self._current_info += ", mask" + self.mask_evaluator.current_info()
|
|
1146
|
+
|
|
1147
|
+
def num_examples(self):
|
|
1148
|
+
return self.box_evaluator.num_examples()
|
|
1149
|
+
|
|
1150
|
+
def evaluate(self):
|
|
1151
|
+
res = self.box_evaluator.evaluate()
|
|
1152
|
+
if self.mask_evaluator is not None:
|
|
1153
|
+
res1 = self.mask_evaluator.evaluate()
|
|
1154
|
+
return res,res1
|
|
1155
|
+
return res
|
|
1156
|
+
|
|
1157
|
+
def show(self,name=""):
|
|
1158
|
+
self.box_evaluator.show(name=name)
|
|
1159
|
+
if self.mask_evaluator is not None:
|
|
1160
|
+
self.mask_evaluator.show(name=name)
|
|
1161
|
+
|
|
1162
|
+
def to_string(self):
|
|
1163
|
+
if self.mask_evaluator is not None:
|
|
1164
|
+
return self.box_evaluator.to_string()+";"+self.mask_evaluator.to_string()
|
|
1165
|
+
else:
|
|
1166
|
+
return self.box_evaluator.to_string()
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
@METRICS_REGISTRY.register()
|
|
1170
|
+
class OneClassesCOCOEvaluation(BaseMetrics):
|
|
1171
|
+
'''
|
|
1172
|
+
num_classes: 不包含背景
|
|
1173
|
+
'''
|
|
1174
|
+
def __init__(self,categories_list=None,num_classes=None,mask_on=False,label_trans=None,classes_begin_value=1,**kwargs):
|
|
1175
|
+
print(f"Init OneClassesCOCOEvaluation")
|
|
1176
|
+
super().__init__(**kwargs)
|
|
1177
|
+
self.box_evaluator = COCOBoxEvaluation(categories_list=categories_list,
|
|
1178
|
+
num_classes=num_classes,
|
|
1179
|
+
label_trans=label_trans,
|
|
1180
|
+
classes_begin_value=classes_begin_value,
|
|
1181
|
+
one_classes=True,
|
|
1182
|
+
**kwargs)
|
|
1183
|
+
self.mask_evaluator = None
|
|
1184
|
+
if mask_on:
|
|
1185
|
+
self.mask_evaluator = COCOMaskEvaluation(categories_list=categories_list,
|
|
1186
|
+
num_classes=num_classes,
|
|
1187
|
+
label_trans=label_trans,
|
|
1188
|
+
classes_begin_value=classes_begin_value,
|
|
1189
|
+
one_classes=True,
|
|
1190
|
+
**kwargs)
|
|
1191
|
+
def __call__(self, *args, **kwargs):
|
|
1192
|
+
self.box_evaluator(*args,**kwargs)
|
|
1193
|
+
self._current_info = self.box_evaluator.current_info()
|
|
1194
|
+
if self.mask_evaluator is not None:
|
|
1195
|
+
self.mask_evaluator(*args,**kwargs)
|
|
1196
|
+
self._current_info += ", mask" + self.mask_evaluator.current_info()
|
|
1197
|
+
|
|
1198
|
+
def num_examples(self):
|
|
1199
|
+
return self.box_evaluator.num_examples()
|
|
1200
|
+
|
|
1201
|
+
def evaluate(self):
|
|
1202
|
+
res = self.box_evaluator.evaluate()
|
|
1203
|
+
if self.mask_evaluator is not None:
|
|
1204
|
+
res1 = self.mask_evaluator.evaluate()
|
|
1205
|
+
return res,res1
|
|
1206
|
+
return res
|
|
1207
|
+
|
|
1208
|
+
def show(self,name=""):
|
|
1209
|
+
self.box_evaluator.show(name=name)
|
|
1210
|
+
if self.mask_evaluator is not None:
|
|
1211
|
+
self.mask_evaluator.show(name=name)
|
|
1212
|
+
|
|
1213
|
+
def to_string(self):
|
|
1214
|
+
if self.mask_evaluator is not None:
|
|
1215
|
+
return self.box_evaluator.to_string()+";"+self.mask_evaluator.to_string()
|
|
1216
|
+
else:
|
|
1217
|
+
return self.box_evaluator.to_string()
|
|
1218
|
+
|
|
1219
|
+
@METRICS_REGISTRY.register()
|
|
1220
|
+
class COCOKeypointsEvaluation(BaseMetrics):
|
|
1221
|
+
def __init__(self,num_joints,categories="person",oks_sigmas=None):
|
|
1222
|
+
categories_keypoints = []
|
|
1223
|
+
for i in range(num_joints):
|
|
1224
|
+
categories_keypoints.append({"id":i,"name":f"KP{i}"})
|
|
1225
|
+
self.coco_evaluator = coco_evaluation.CocoKeypointEvaluator(
|
|
1226
|
+
category_id=1,
|
|
1227
|
+
category_keypoints=categories_keypoints,
|
|
1228
|
+
class_text=categories,
|
|
1229
|
+
oks_sigmas=oks_sigmas)
|
|
1230
|
+
self.image_id = 0
|
|
1231
|
+
self.cached_values = {}
|
|
1232
|
+
'''
|
|
1233
|
+
gtboxes:[N,4]
|
|
1234
|
+
img_size:[H,W]
|
|
1235
|
+
gtkeypoitns:[N,num_joints,3]
|
|
1236
|
+
boxes: [M,4]
|
|
1237
|
+
kps: [M,num_joints,3]
|
|
1238
|
+
'''
|
|
1239
|
+
def __call__(self, gtboxes,gtkeypoints,kps,scores,area=None,iscrowd=None):
|
|
1240
|
+
self.image_id += 1
|
|
1241
|
+
self.add_groundtruth(self.image_id,gtboxes,gtkeypoints,area=area,iscrowd=iscrowd)
|
|
1242
|
+
self.add_detection(self.image_id,kps,scores)
|
|
1243
|
+
|
|
1244
|
+
def add_groundtruth(self, image_id,gtboxes,gtkeypoints,area=None,iscrowd=None):
|
|
1245
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
1246
|
+
gtboxes = np.array(gtboxes)
|
|
1247
|
+
if not isinstance(gtkeypoints,np.ndarray):
|
|
1248
|
+
gtkeypoints = np.array(gtkeypoints)
|
|
1249
|
+
|
|
1250
|
+
if gtboxes.shape[0]>0:
|
|
1251
|
+
groundtruth_dict={
|
|
1252
|
+
standard_fields.InputDataFields.groundtruth_boxes:
|
|
1253
|
+
gtboxes,
|
|
1254
|
+
standard_fields.InputDataFields.groundtruth_classes:np.ones([gtboxes.shape[0]],dtype=np.int32),
|
|
1255
|
+
}
|
|
1256
|
+
if iscrowd is not None:
|
|
1257
|
+
if not isinstance(iscrowd,np.ndarray):
|
|
1258
|
+
iscrowd = np.array(iscrowd)
|
|
1259
|
+
groundtruth_dict[standard_fields.InputDataFields.groundtruth_is_crowd] = iscrowd
|
|
1260
|
+
if area is not None:
|
|
1261
|
+
if not isinstance(area,np.ndarray):
|
|
1262
|
+
area = np.array(area)
|
|
1263
|
+
groundtruth_dict[standard_fields.InputDataFields.groundtruth_area] = area
|
|
1264
|
+
groundtruth_dict[standard_fields.InputDataFields.groundtruth_keypoints] = gtkeypoints[...,:2]
|
|
1265
|
+
groundtruth_dict[standard_fields.InputDataFields.groundtruth_keypoint_visibilities] = gtkeypoints[...,2]
|
|
1266
|
+
self.coco_evaluator.add_single_ground_truth_image_info(
|
|
1267
|
+
image_id=str(image_id),
|
|
1268
|
+
groundtruth_dict=groundtruth_dict)
|
|
1269
|
+
|
|
1270
|
+
def add_detection(self, image_id,kps,scores):
|
|
1271
|
+
if not isinstance(kps,np.ndarray):
|
|
1272
|
+
kps = np.array(kps)
|
|
1273
|
+
if not isinstance(scores,np.ndarray):
|
|
1274
|
+
scores = np.array(scores)
|
|
1275
|
+
|
|
1276
|
+
if kps.shape[0]>0:
|
|
1277
|
+
detections_dict={
|
|
1278
|
+
standard_fields.DetectionResultFields.detection_boxes:np.zeros([kps.shape[0],4],dtype=np.float32),
|
|
1279
|
+
standard_fields.DetectionResultFields.detection_scores: scores,
|
|
1280
|
+
standard_fields.DetectionResultFields.detection_keypoints: kps[...,:2],
|
|
1281
|
+
standard_fields.DetectionResultFields.detection_classes:np.ones([kps.shape[0]],dtype=np.int32),
|
|
1282
|
+
}
|
|
1283
|
+
self.coco_evaluator.add_single_detected_image_info(
|
|
1284
|
+
image_id=str(image_id),
|
|
1285
|
+
detections_dict=detections_dict)
|
|
1286
|
+
|
|
1287
|
+
def num_examples(self):
|
|
1288
|
+
if '_image_ids_with_detections' in self.coco_evaluator.__dict__:
|
|
1289
|
+
return len(self.coco_evaluator._image_ids_with_detections)
|
|
1290
|
+
elif '_image_ids' in self.coco_evaluator.__dict__:
|
|
1291
|
+
return len(self.coco_evaluator._image_ids)
|
|
1292
|
+
else:
|
|
1293
|
+
raise RuntimeError("Error evaluator type.")
|
|
1294
|
+
|
|
1295
|
+
def evaluate(self):
|
|
1296
|
+
print(f"Test size {self.num_examples()}")
|
|
1297
|
+
res = self.coco_evaluator.evaluate()
|
|
1298
|
+
for k,v in res.items():
|
|
1299
|
+
index = k.find("/")
|
|
1300
|
+
if index>0:
|
|
1301
|
+
k = k[index+1:]
|
|
1302
|
+
self.cached_values[k] = v
|
|
1303
|
+
return res
|
|
1304
|
+
|
|
1305
|
+
def show(self,name=""):
|
|
1306
|
+
sys.stdout.flush()
|
|
1307
|
+
print(f"Test size {self.num_examples()}")
|
|
1308
|
+
res = self.coco_evaluator.evaluate()
|
|
1309
|
+
str0 = "|配置|"
|
|
1310
|
+
str1 = "|---|"
|
|
1311
|
+
str2 = f"|{name}|"
|
|
1312
|
+
for k,v in res.items():
|
|
1313
|
+
index = k.find("/")
|
|
1314
|
+
if index>0:
|
|
1315
|
+
k = k[index+1:]
|
|
1316
|
+
self.cached_values[k] = v
|
|
1317
|
+
str0 += f"{k}|"
|
|
1318
|
+
str1 += "---|"
|
|
1319
|
+
str2 += f"{v:.3f}|"
|
|
1320
|
+
print(str0)
|
|
1321
|
+
print(str1)
|
|
1322
|
+
print(str2)
|
|
1323
|
+
sys.stdout.flush()
|
|
1324
|
+
return res
|
|
1325
|
+
|
|
1326
|
+
def to_string(self):
|
|
1327
|
+
if 'mAP' in self.cached_values and 'mAP@.50IOU' in self.cached_values:
|
|
1328
|
+
return f"{self.cached_values['mAP']:.3f}/{self.cached_values['mAP@.50IOU']:.3f}"
|
|
1329
|
+
else:
|
|
1330
|
+
return f"N.A."
|
|
1331
|
+
|
|
1332
|
+
@METRICS_REGISTRY.register()
|
|
1333
|
+
class ClassesWiseModelPerformace(BaseMetrics):
|
|
1334
|
+
def __init__(self,num_classes,threshold=0.5,classes_begin_value=1,model_type=COCOEvaluation,
|
|
1335
|
+
model_args={},
|
|
1336
|
+
label_trans=None,
|
|
1337
|
+
classes=None,
|
|
1338
|
+
**kwargs):
|
|
1339
|
+
super().__init__(**kwargs)
|
|
1340
|
+
self.num_classes = num_classes
|
|
1341
|
+
self.clases_begin_value = classes_begin_value
|
|
1342
|
+
model_args['classes_begin_value'] = classes_begin_value
|
|
1343
|
+
|
|
1344
|
+
if isinstance(model_type,(str,bytes)):
|
|
1345
|
+
print(model_type)
|
|
1346
|
+
model_type = METRICS_REGISTRY.get(model_type)
|
|
1347
|
+
print(model_type)
|
|
1348
|
+
print(model_type)
|
|
1349
|
+
|
|
1350
|
+
if classes is None:
|
|
1351
|
+
classes = [f"C{i+1}" for i in range(num_classes)]
|
|
1352
|
+
|
|
1353
|
+
self.classes = classes
|
|
1354
|
+
|
|
1355
|
+
self.data = []
|
|
1356
|
+
for i in range(self.num_classes):
|
|
1357
|
+
self.data.append(model_type(num_classes=num_classes,**model_args))
|
|
1358
|
+
self.mp = model_type(num_classes=num_classes,**model_args)
|
|
1359
|
+
self.label_trans = label_trans
|
|
1360
|
+
self.have_data = np.zeros([num_classes],dtype=np.bool)
|
|
1361
|
+
|
|
1362
|
+
@staticmethod
|
|
1363
|
+
def select_bboxes_and_labels(bboxes,labels,classes):
|
|
1364
|
+
if len(labels) == 0:
|
|
1365
|
+
return np.array([],dtype=np.float32),np.array([],dtype=np.int32),np.array([],dtype=np.bool)
|
|
1366
|
+
if not isinstance(labels,np.ndarray):
|
|
1367
|
+
labels = np.array(labels)
|
|
1368
|
+
mask = np.equal(labels,classes)
|
|
1369
|
+
rbboxes = bboxes[mask,:]
|
|
1370
|
+
rlabels = labels[mask]
|
|
1371
|
+
return rbboxes,rlabels,mask
|
|
1372
|
+
|
|
1373
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=None,use_relative_coord=False,is_crowd=None):
|
|
1374
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
1375
|
+
gtboxes = np.array(gtboxes)
|
|
1376
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
1377
|
+
gtlabels = np.array(gtlabels)
|
|
1378
|
+
if not isinstance(labels,np.ndarray):
|
|
1379
|
+
labels = np.array(labels)
|
|
1380
|
+
if self.label_trans is not None:
|
|
1381
|
+
gtlabels = self.label_trans(gtlabels)
|
|
1382
|
+
labels = self.label_trans(labels)
|
|
1383
|
+
|
|
1384
|
+
if is_crowd is not None and not isinstance(is_crowd,np.ndarray):
|
|
1385
|
+
is_crowd = np.array(is_crowd)
|
|
1386
|
+
|
|
1387
|
+
for i in range(self.num_classes):
|
|
1388
|
+
classes = i+self.clases_begin_value
|
|
1389
|
+
lgtboxes,lgtlabels,lgtmask = self.select_bboxes_and_labels(gtboxes,gtlabels,classes)
|
|
1390
|
+
lboxes,llabels,lmask = self.select_bboxes_and_labels(boxes,labels,classes)
|
|
1391
|
+
if is_crowd is not None:
|
|
1392
|
+
lis_crowd = is_crowd[lgtmask]
|
|
1393
|
+
else:
|
|
1394
|
+
lis_crowd = None
|
|
1395
|
+
if probability is not None:
|
|
1396
|
+
lprobs = probability[lmask]
|
|
1397
|
+
else:
|
|
1398
|
+
lprobs = None
|
|
1399
|
+
if (lgtlabels.shape[0]==0) and (llabels.shape[0] ==0):
|
|
1400
|
+
continue
|
|
1401
|
+
self.have_data[i] = True
|
|
1402
|
+
self.data[i](lgtboxes,lgtlabels,lboxes,llabels,lprobs,img_size=img_size,use_relative_coord=use_relative_coord,is_crowd=lis_crowd)
|
|
1403
|
+
|
|
1404
|
+
self._current_info = ""
|
|
1405
|
+
|
|
1406
|
+
return self.mp(gtboxes,gtlabels,boxes,labels,probability,is_crowd=is_crowd,img_size=img_size,
|
|
1407
|
+
use_relative_coord=use_relative_coord)
|
|
1408
|
+
|
|
1409
|
+
def show(self):
|
|
1410
|
+
sys.stdout.flush()
|
|
1411
|
+
for i in range(self.num_classes):
|
|
1412
|
+
if not self.have_data[i]:
|
|
1413
|
+
continue
|
|
1414
|
+
classes = i+self.clases_begin_value
|
|
1415
|
+
print(f"Classes:{classes}")
|
|
1416
|
+
try:
|
|
1417
|
+
self.data[i].show()
|
|
1418
|
+
except:
|
|
1419
|
+
print("N.A.")
|
|
1420
|
+
pass
|
|
1421
|
+
self.classes_wise_results = {}
|
|
1422
|
+
sys.stdout.flush()
|
|
1423
|
+
print(f"---------------------------------------------------------------")
|
|
1424
|
+
print(f"All classes")
|
|
1425
|
+
sys.stdout.flush()
|
|
1426
|
+
self.mp.show()
|
|
1427
|
+
sys.stdout.flush()
|
|
1428
|
+
print(f"Per classes")
|
|
1429
|
+
str0 = "|配置|"
|
|
1430
|
+
str1 = "|---|"
|
|
1431
|
+
str2 = f"|{self.cfg_name}|"
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
#总体
|
|
1435
|
+
str0 += f"ALL|"
|
|
1436
|
+
str1 += "---|"
|
|
1437
|
+
str2 += f"{str(self.mp.to_string())}|"
|
|
1438
|
+
|
|
1439
|
+
for i in range(self.num_classes):
|
|
1440
|
+
classes_id = i+1
|
|
1441
|
+
str0 += f"{self.classes[i]}|"
|
|
1442
|
+
str1 += "---|"
|
|
1443
|
+
str2 += f"{str(self.data[i].to_string())}|"
|
|
1444
|
+
try:
|
|
1445
|
+
keys = ['mAP', 'mAP (small)', 'mAP (medium)', 'mAP (large)']
|
|
1446
|
+
if hasattr(self.data[i], "box_evaluator"):
|
|
1447
|
+
d = self.data[i].box_evaluator.cached_values
|
|
1448
|
+
else:
|
|
1449
|
+
d = self.data[i].cached_values
|
|
1450
|
+
values = [d[k] for k in keys]
|
|
1451
|
+
self.classes_wise_results[classes_id] = values
|
|
1452
|
+
except:
|
|
1453
|
+
self.classes_wise_results[classes_id] = [-1.0]*len(keys)
|
|
1454
|
+
print(str0)
|
|
1455
|
+
print(str1)
|
|
1456
|
+
print(str2)
|
|
1457
|
+
#wmlu.show_dict(self.classes_wise_results,format="{:.3f}")
|
|
1458
|
+
print("Summary")
|
|
1459
|
+
wmlu.show_dict(self.classes_wise_results)
|
|
1460
|
+
sys.stdout.flush()
|
|
1461
|
+
return str2
|
|
1462
|
+
|
|
1463
|
+
def __getattr__(self, item):
|
|
1464
|
+
if item=="mAP":
|
|
1465
|
+
return self.mp.mAP
|
|
1466
|
+
elif item =="recall":
|
|
1467
|
+
return self.mp.recall
|
|
1468
|
+
elif item=="precision":
|
|
1469
|
+
return self.mp.precision
|
|
1470
|
+
|
|
1471
|
+
def evaluate(self):
|
|
1472
|
+
[d.evaluate() for d in self.data]
|
|
1473
|
+
self.mp.evaluate()
|
|
1474
|
+
|
|
1475
|
+
def detail_valus(self):
|
|
1476
|
+
return [d.detail_valus() for d in self.data]
|
|
1477
|
+
|
|
1478
|
+
@METRICS_REGISTRY.register()
|
|
1479
|
+
class SizeWiseModelPerformace(BaseMetrics):
|
|
1480
|
+
def __init__(self,num_classes,sizes=[100],threshold=0.5,classes_begin_value=1,model_type=COCOEvaluation,
|
|
1481
|
+
model_args={},
|
|
1482
|
+
label_trans=None,
|
|
1483
|
+
**kwargs):
|
|
1484
|
+
super().__init__(**kwargs)
|
|
1485
|
+
self.num_classes = num_classes
|
|
1486
|
+
self.clases_begin_value = classes_begin_value
|
|
1487
|
+
model_args['classes_begin_value'] = classes_begin_value
|
|
1488
|
+
|
|
1489
|
+
if isinstance(model_type,(str,bytes)):
|
|
1490
|
+
model_type = METRICS_REGISTRY.get(model_type)
|
|
1491
|
+
|
|
1492
|
+
self.sizes = sizes
|
|
1493
|
+
self.data = []
|
|
1494
|
+
for i in range(len(sizes)+1):
|
|
1495
|
+
self.data.append(model_type(num_classes=num_classes,**model_args))
|
|
1496
|
+
self.mp = model_type(num_classes=num_classes,**model_args)
|
|
1497
|
+
self.label_trans = label_trans
|
|
1498
|
+
self.have_data = np.zeros([len(self.data)],dtype=np.bool)
|
|
1499
|
+
|
|
1500
|
+
def get_idx(self,gtbboxes):
|
|
1501
|
+
'''
|
|
1502
|
+
根据最大bboxes的大小确定
|
|
1503
|
+
'''
|
|
1504
|
+
wh = gtbboxes[...,2:]-gtbboxes[...,:2]
|
|
1505
|
+
size = np.max(wh)
|
|
1506
|
+
for i,s in enumerate(self.sizes):
|
|
1507
|
+
if size<s:
|
|
1508
|
+
return i
|
|
1509
|
+
return len(self.sizes)
|
|
1510
|
+
|
|
1511
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=None,use_relative_coord=False,is_crowd=None):
|
|
1512
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
1513
|
+
gtboxes = np.array(gtboxes)
|
|
1514
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
1515
|
+
gtlabels = np.array(gtlabels)
|
|
1516
|
+
if not isinstance(labels,np.ndarray):
|
|
1517
|
+
labels = np.array(labels)
|
|
1518
|
+
if self.label_trans is not None:
|
|
1519
|
+
gtlabels = self.label_trans(gtlabels)
|
|
1520
|
+
labels = self.label_trans(labels)
|
|
1521
|
+
|
|
1522
|
+
if is_crowd is not None and not isinstance(is_crowd,np.ndarray):
|
|
1523
|
+
is_crowd = np.array(is_crowd)
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
idx = self.get_idx(gtboxes)
|
|
1527
|
+
self.data[idx](gtboxes,gtlabels,boxes,labels,probability,is_crowd=is_crowd,img_size=img_size,
|
|
1528
|
+
use_relative_coord=use_relative_coord)
|
|
1529
|
+
self.have_data[idx] = True
|
|
1530
|
+
|
|
1531
|
+
self._current_info = ""
|
|
1532
|
+
|
|
1533
|
+
return self.mp(gtboxes,gtlabels,boxes,labels,probability,is_crowd=is_crowd,img_size=img_size,
|
|
1534
|
+
use_relative_coord=use_relative_coord)
|
|
1535
|
+
|
|
1536
|
+
def show(self):
|
|
1537
|
+
sys.stdout.flush()
|
|
1538
|
+
names = []
|
|
1539
|
+
for i,s in enumerate(self.sizes):
|
|
1540
|
+
names.append(f"<={s}")
|
|
1541
|
+
names.append(f">{self.sizes[-1]}")
|
|
1542
|
+
for i in range(len(self.data)):
|
|
1543
|
+
if not self.have_data[i]:
|
|
1544
|
+
continue
|
|
1545
|
+
print(f"{names[i]}")
|
|
1546
|
+
try:
|
|
1547
|
+
self.data[i].show()
|
|
1548
|
+
except:
|
|
1549
|
+
print("N.A.")
|
|
1550
|
+
pass
|
|
1551
|
+
sys.stdout.flush()
|
|
1552
|
+
print(f"---------------------------------------------------------------")
|
|
1553
|
+
print(f"All sizes")
|
|
1554
|
+
sys.stdout.flush()
|
|
1555
|
+
self.mp.show()
|
|
1556
|
+
sys.stdout.flush()
|
|
1557
|
+
print(f"Per sizes")
|
|
1558
|
+
str0 = "|配置|"
|
|
1559
|
+
str1 = "|---|"
|
|
1560
|
+
str2 = f"|{self.cfg_name}|"
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
#总体
|
|
1564
|
+
str0 += f"ALL|"
|
|
1565
|
+
str1 += "---|"
|
|
1566
|
+
str2 += f"{str(self.mp.to_string())}|"
|
|
1567
|
+
|
|
1568
|
+
for i in range(len(self.data)):
|
|
1569
|
+
str0 += f"{names[i]}|"
|
|
1570
|
+
str1 += "---|"
|
|
1571
|
+
str2 += f"{str(self.data[i].to_string())}|"
|
|
1572
|
+
print(str0)
|
|
1573
|
+
print(str1)
|
|
1574
|
+
print(str2)
|
|
1575
|
+
#wmlu.show_dict(self.classes_wise_results,format="{:.3f}")
|
|
1576
|
+
sys.stdout.flush()
|
|
1577
|
+
return str2
|
|
1578
|
+
|
|
1579
|
+
def __getattr__(self, item):
|
|
1580
|
+
if item=="mAP":
|
|
1581
|
+
return self.mp.mAP
|
|
1582
|
+
elif item =="recall":
|
|
1583
|
+
return self.mp.recall
|
|
1584
|
+
elif item=="precision":
|
|
1585
|
+
return self.mp.precision
|
|
1586
|
+
|
|
1587
|
+
@METRICS_REGISTRY.register()
|
|
1588
|
+
class SubsetsModelPerformace(BaseMetrics):
|
|
1589
|
+
def __init__(self, num_classes, sub_sets,threshold=0.5, model_type=COCOEvaluation, classes_begin_value=1,model_args={},
|
|
1590
|
+
label_trans=None,
|
|
1591
|
+
**kwargs):
|
|
1592
|
+
'''
|
|
1593
|
+
|
|
1594
|
+
:param num_classes: 不包含背景
|
|
1595
|
+
:param sub_sets: list(list):如[[1,2],[3,4,5]]表示label 1,2一组进行评估,label 3 ,4,5一组进行评估
|
|
1596
|
+
:param threshold:
|
|
1597
|
+
:param classes_begin_value:
|
|
1598
|
+
:param model_type:
|
|
1599
|
+
:param model_args:
|
|
1600
|
+
:param label_trans:
|
|
1601
|
+
'''
|
|
1602
|
+
model_args['classes_begin_value'] = classes_begin_value
|
|
1603
|
+
self.num_classes = num_classes
|
|
1604
|
+
self.data = []
|
|
1605
|
+
self.sub_sets = sub_sets
|
|
1606
|
+
for i in range(len(sub_sets)):
|
|
1607
|
+
self.data.append(model_type(num_classes=num_classes, **model_args))
|
|
1608
|
+
self.mp = model_type(num_classes=num_classes, **model_args)
|
|
1609
|
+
self.label_trans = label_trans
|
|
1610
|
+
|
|
1611
|
+
@staticmethod
|
|
1612
|
+
def select_bboxes_and_labels(bboxes, labels, classes):
|
|
1613
|
+
if len(labels) == 0:
|
|
1614
|
+
return np.array([], dtype=np.float32), np.array([], dtype=np.int32), np.array([], dtype=np.bool)
|
|
1615
|
+
|
|
1616
|
+
if not isinstance(labels, np.ndarray):
|
|
1617
|
+
labels = np.array(labels)
|
|
1618
|
+
mask = np.zeros_like(labels, dtype=np.bool)
|
|
1619
|
+
for i,l in enumerate(labels):
|
|
1620
|
+
if l in classes:
|
|
1621
|
+
mask[i] = True
|
|
1622
|
+
rbboxes = bboxes[mask, :]
|
|
1623
|
+
rlabels = labels[mask]
|
|
1624
|
+
return rbboxes, rlabels,mask
|
|
1625
|
+
|
|
1626
|
+
def __call__(self, gtboxes, gtlabels, boxes, labels, probability=None, img_size=None):
|
|
1627
|
+
if not isinstance(gtboxes, np.ndarray):
|
|
1628
|
+
gtboxes = np.array(gtboxes)
|
|
1629
|
+
if not isinstance(gtlabels, np.ndarray):
|
|
1630
|
+
gtlabels = np.array(gtlabels)
|
|
1631
|
+
if not isinstance(labels, np.ndarray):
|
|
1632
|
+
labels = np.array(labels)
|
|
1633
|
+
if self.label_trans is not None:
|
|
1634
|
+
gtlabels = self.label_trans(gtlabels)
|
|
1635
|
+
labels = self.label_trans(labels)
|
|
1636
|
+
|
|
1637
|
+
for i,sub_set_labels in enumerate(self.sub_sets):
|
|
1638
|
+
lgtboxes, lgtlabels,_ = self.select_bboxes_and_labels(gtboxes, gtlabels, sub_set_labels)
|
|
1639
|
+
lboxes, llabels,lmask = self.select_bboxes_and_labels(boxes, labels, sub_set_labels)
|
|
1640
|
+
if probability is not None:
|
|
1641
|
+
lprobs = probability[lmask]
|
|
1642
|
+
else:
|
|
1643
|
+
lprobs = None
|
|
1644
|
+
if lgtlabels.shape[0] == 0:
|
|
1645
|
+
continue
|
|
1646
|
+
self.data[i](lgtboxes, lgtlabels, lboxes, llabels, lprobs,img_size=img_size)
|
|
1647
|
+
return self.mp(gtboxes, gtlabels, boxes, labels)
|
|
1648
|
+
|
|
1649
|
+
def current_info(self):
|
|
1650
|
+
return self.mp.current_info()
|
|
1651
|
+
|
|
1652
|
+
def show(self):
|
|
1653
|
+
for i,sub_set_labels in enumerate(self.sub_sets):
|
|
1654
|
+
print(f"Classes:{sub_set_labels}")
|
|
1655
|
+
self.data[i].show()
|
|
1656
|
+
str0 = "|配置|"
|
|
1657
|
+
str1 = "|---|"
|
|
1658
|
+
str2 = "||"
|
|
1659
|
+
for i,sub_set_labels in enumerate(self.sub_sets):
|
|
1660
|
+
str0 += f"S{sub_set_labels}|"
|
|
1661
|
+
str1 += "---|"
|
|
1662
|
+
str2 += f"{str(self.data[i].to_string())}|"
|
|
1663
|
+
print(str0)
|
|
1664
|
+
print(str1)
|
|
1665
|
+
print(str2)
|
|
1666
|
+
|
|
1667
|
+
def __getattr__(self, item):
|
|
1668
|
+
if item == "mAP":
|
|
1669
|
+
return self.mp.mAP
|
|
1670
|
+
elif item == "recall":
|
|
1671
|
+
return self.mp.recall
|
|
1672
|
+
elif item == "precision":
|
|
1673
|
+
return self.mp.precision
|
|
1674
|
+
|
|
1675
|
+
@METRICS_REGISTRY.register()
|
|
1676
|
+
class MeanIOU(BaseMetrics):
|
|
1677
|
+
def __init__(self,num_classes,*args,**kwargs):
|
|
1678
|
+
self.intersection = np.zeros(shape=[num_classes],dtype=np.int64)
|
|
1679
|
+
self.union = np.zeros(shape=[num_classes],dtype=np.int64)
|
|
1680
|
+
self.num_classes = num_classes
|
|
1681
|
+
|
|
1682
|
+
def get_per_classes_iou(self):
|
|
1683
|
+
return self.intersection/np.maximum(self.union,1e-8)
|
|
1684
|
+
|
|
1685
|
+
def get_mean_iou(self):
|
|
1686
|
+
return np.mean(self.get_per_classes_iou())
|
|
1687
|
+
|
|
1688
|
+
|
|
1689
|
+
def __call__(self, gtlabels,predictions):
|
|
1690
|
+
all_equal = np.equal(gtlabels,predictions)
|
|
1691
|
+
for i in range(1,self.num_classes+1):
|
|
1692
|
+
mask = np.equal(gtlabels,i)
|
|
1693
|
+
t_int = np.sum(all_equal[mask].astype(np.int64))
|
|
1694
|
+
t_data0 = np.sum(np.equal(gtlabels,i).astype(np.int64))
|
|
1695
|
+
t_data1 = np.sum(np.equal(predictions,i).astype(np.int64))
|
|
1696
|
+
t_union = t_data0+t_data1-t_int
|
|
1697
|
+
self.intersection[i-1] += t_int
|
|
1698
|
+
self.union[i-1] += t_union
|
|
1699
|
+
|
|
1700
|
+
|
|
1701
|
+
def show(self,name):
|
|
1702
|
+
str0 = "|配置|mIOU|"
|
|
1703
|
+
str1 = "|---|---|"
|
|
1704
|
+
str2 = f"|{name}|{self.get_mean_iou():.4f}"
|
|
1705
|
+
data = self.get_per_classes_iou()
|
|
1706
|
+
for i in range(self.num_classes):
|
|
1707
|
+
str0 += f"C{i+1}|"
|
|
1708
|
+
str1 += "---|"
|
|
1709
|
+
str2 += f"{data[i]:.3f}|"
|
|
1710
|
+
print(str0)
|
|
1711
|
+
print(str1)
|
|
1712
|
+
print(str2)
|
|
1713
|
+
|
|
1714
|
+
def coco_keypoint_eval_file(gt_file, res_file):
|
|
1715
|
+
coco = COCO(gt_file)
|
|
1716
|
+
coco_dt = coco.loadRes(res_file)
|
|
1717
|
+
coco_eval = COCOeval(coco, coco_dt, 'keypoints')
|
|
1718
|
+
coco_eval.params.useSegm = None
|
|
1719
|
+
coco_eval.evaluate()
|
|
1720
|
+
coco_eval.accumulate()
|
|
1721
|
+
coco_eval.summarize()
|
|
1722
|
+
|
|
1723
|
+
stats_names = ['AP', 'Ap .5', 'AP .75', 'AP (M)', 'AP (L)', 'AR', 'AR .5', 'AR .75', 'AR (M)', 'AR (L)']
|
|
1724
|
+
|
|
1725
|
+
info_str = []
|
|
1726
|
+
for ind, name in enumerate(stats_names):
|
|
1727
|
+
info_str.append((name, coco_eval.stats[ind]))
|
|
1728
|
+
|
|
1729
|
+
return info_str
|
|
1730
|
+
|
|
1731
|
+
def coco_bbox_eval_file(gt_file, res_file):
|
|
1732
|
+
coco = COCO(gt_file)
|
|
1733
|
+
coco_dt = coco.loadRes(res_file)
|
|
1734
|
+
coco_eval = COCOeval(coco, coco_dt, 'bbox')
|
|
1735
|
+
coco_eval.params.useSegm = None
|
|
1736
|
+
coco_eval.evaluate()
|
|
1737
|
+
coco_eval.accumulate()
|
|
1738
|
+
coco_eval.summarize()
|
|
1739
|
+
|
|
1740
|
+
stats_names = ['AP', 'Ap .5', 'AP .75', 'AP (M)', 'AP (L)', 'AR', 'AR .5', 'AR .75', 'AR (M)', 'AR (L)']
|
|
1741
|
+
|
|
1742
|
+
info_str = []
|
|
1743
|
+
for ind, name in enumerate(stats_names):
|
|
1744
|
+
info_str.append((name, coco_eval.stats[ind]))
|
|
1745
|
+
|
|
1746
|
+
return info_str
|
|
1747
|
+
|
|
1748
|
+
@METRICS_REGISTRY.register()
|
|
1749
|
+
class WMAP(BaseMetrics):
|
|
1750
|
+
def __init__(self,categories_list=None,num_classes=None,mask_on=False,label_trans=None,classes_begin_value=1,threshold=0.5):
|
|
1751
|
+
if categories_list is None:
|
|
1752
|
+
print(f"WARNING: Use default categories list, start classes is {classes_begin_value}")
|
|
1753
|
+
self.categories_list = [{"id":x+classes_begin_value,"name":str(x+classes_begin_value)} for x in range(num_classes)]
|
|
1754
|
+
else:
|
|
1755
|
+
self.categories_list = categories_list
|
|
1756
|
+
self.label_trans = label_trans
|
|
1757
|
+
self.image_id = 0
|
|
1758
|
+
self.num_classes = num_classes
|
|
1759
|
+
self.cached_values = {}
|
|
1760
|
+
self.a_gtbboxes = []
|
|
1761
|
+
self.a_gtlabels = []
|
|
1762
|
+
self.a_bboxes = []
|
|
1763
|
+
self.a_labels = []
|
|
1764
|
+
self.a_scores = []
|
|
1765
|
+
self.threshold = 0.5
|
|
1766
|
+
self.map = None
|
|
1767
|
+
'''
|
|
1768
|
+
gtboxes:[N,4]
|
|
1769
|
+
gtlabels:[N]
|
|
1770
|
+
img_size:[H,W]
|
|
1771
|
+
gtmasks:[N,H,W]
|
|
1772
|
+
'''
|
|
1773
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
1774
|
+
gtmasks=None,
|
|
1775
|
+
masks=None,is_crowd=None,use_relative_coord=False):
|
|
1776
|
+
if probability is None:
|
|
1777
|
+
probability = np.ones_like(labels,dtype=np.float32)
|
|
1778
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
1779
|
+
gtboxes = np.array(gtboxes)
|
|
1780
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
1781
|
+
gtlabels = np.array(gtlabels)
|
|
1782
|
+
if not isinstance(boxes,np.ndarray):
|
|
1783
|
+
boxes = np.array(boxes)
|
|
1784
|
+
if not isinstance(labels,np.ndarray):
|
|
1785
|
+
labels = np.array(labels)
|
|
1786
|
+
if self.label_trans is not None:
|
|
1787
|
+
gtlabels = self.label_trans(gtlabels)
|
|
1788
|
+
labels = self.label_trans(labels)
|
|
1789
|
+
if probability is not None and not isinstance(probability,np.ndarray):
|
|
1790
|
+
probability = np.array(probability)
|
|
1791
|
+
|
|
1792
|
+
cur_ap = getmAP(gtboxes=gtboxes,
|
|
1793
|
+
gtlabels=gtlabels,
|
|
1794
|
+
boxes=boxes,
|
|
1795
|
+
labels=labels,
|
|
1796
|
+
probability=probability,
|
|
1797
|
+
is_crowd=is_crowd)
|
|
1798
|
+
self._current_info = f"ap={cur_ap}"
|
|
1799
|
+
|
|
1800
|
+
if gtlabels.shape[0]>0:
|
|
1801
|
+
if use_relative_coord:
|
|
1802
|
+
gtboxes = gtboxes*[[img_size[0],img_size[1],img_size[0],img_size[1]]]
|
|
1803
|
+
gtlabels = gtlabels+self.image_id*self.num_classes
|
|
1804
|
+
self.a_gtbboxes.append(gtboxes)
|
|
1805
|
+
self.a_gtlabels.append(gtlabels)
|
|
1806
|
+
if labels.shape[0]>0 and gtlabels.shape[0]>0:
|
|
1807
|
+
if use_relative_coord:
|
|
1808
|
+
boxes = boxes*[[img_size[0],img_size[1],img_size[0],img_size[1]]]
|
|
1809
|
+
labels = gtlabels+self.image_id*self.num_classes
|
|
1810
|
+
self.a_bboxes.append(boxes)
|
|
1811
|
+
self.a_labels.append(labels)
|
|
1812
|
+
self.a_scores.append(probability)
|
|
1813
|
+
self.image_id += 1
|
|
1814
|
+
|
|
1815
|
+
def num_examples(self):
|
|
1816
|
+
return self.image_id
|
|
1817
|
+
|
|
1818
|
+
def evaluate(self):
|
|
1819
|
+
print(f"Test size {self.num_examples()}")
|
|
1820
|
+
gtlabels = np.stack(self.a_gtbboxes,axis=0)
|
|
1821
|
+
gtbboxes = np.stack(self.a_gtbboxes,axis=0)
|
|
1822
|
+
labels = np.stack(self.a_labels,axis=0)
|
|
1823
|
+
bboxes = np.stack(self.a_bboxes,axis=0)
|
|
1824
|
+
scores = np.stack(self.a_scores,axis=0)
|
|
1825
|
+
self.map = getmAP(gtbboxes,gtlabels,bboxes,labels,scores,threshold=self.threshold)
|
|
1826
|
+
|
|
1827
|
+
def show(self,name=""):
|
|
1828
|
+
sys.stdout.flush()
|
|
1829
|
+
print(f"Test size {self.num_examples()}")
|
|
1830
|
+
print(f"mAP={self.map}")
|
|
1831
|
+
return self.map
|
|
1832
|
+
|
|
1833
|
+
def to_string(self):
|
|
1834
|
+
return self.map
|
|
1835
|
+
|
|
1836
|
+
def __repr__(self):
|
|
1837
|
+
return self.to_string()
|
|
1838
|
+
|
|
1839
|
+
def value(self):
|
|
1840
|
+
return self.map
|
|
1841
|
+
|
|
1842
|
+
@METRICS_REGISTRY.register()
|
|
1843
|
+
class DetConfusionMatrix(BaseMetrics):
|
|
1844
|
+
def __init__(self,categories_list=None,num_classes=None,mask_on=False,label_trans=None,classes_begin_value=1,score_thr=0.5,threshold=0.3):
|
|
1845
|
+
super().__init__()
|
|
1846
|
+
if categories_list is None:
|
|
1847
|
+
print(f"WARNING: Use default categories list, start classes is {classes_begin_value}")
|
|
1848
|
+
self.categories_list = [{"id":x+classes_begin_value,"name":str(x+classes_begin_value)} for x in range(num_classes)]
|
|
1849
|
+
else:
|
|
1850
|
+
self.categories_list = categories_list
|
|
1851
|
+
self.num_classes = num_classes
|
|
1852
|
+
self.label_trans = label_trans
|
|
1853
|
+
self.iou_thr = threshold
|
|
1854
|
+
self.score_thr = score_thr
|
|
1855
|
+
self.pred_labels = []
|
|
1856
|
+
self.gt_labels = []
|
|
1857
|
+
self.kernel = ConfusionMatrix(num_classes=self.num_classes+1)
|
|
1858
|
+
self.image_id = 0
|
|
1859
|
+
|
|
1860
|
+
def __call__(self, gtboxes,gtlabels,boxes,labels,probability=None,img_size=[512,512],
|
|
1861
|
+
gtmasks=None,
|
|
1862
|
+
masks=None,is_crowd=None,use_relative_coord=False):
|
|
1863
|
+
if probability is None:
|
|
1864
|
+
probability = np.ones_like(labels,dtype=np.float32)
|
|
1865
|
+
if not isinstance(gtboxes,np.ndarray):
|
|
1866
|
+
gtboxes = np.array(gtboxes)
|
|
1867
|
+
if not isinstance(gtlabels,np.ndarray):
|
|
1868
|
+
gtlabels = np.array(gtlabels)
|
|
1869
|
+
if not isinstance(boxes,np.ndarray):
|
|
1870
|
+
boxes = np.array(boxes)
|
|
1871
|
+
if not isinstance(labels,np.ndarray):
|
|
1872
|
+
labels = np.array(labels)
|
|
1873
|
+
if self.label_trans is not None:
|
|
1874
|
+
gtlabels = self.label_trans(gtlabels)
|
|
1875
|
+
labels = self.label_trans(labels)
|
|
1876
|
+
if probability is not None and not isinstance(probability,np.ndarray):
|
|
1877
|
+
probability = np.array(probability)
|
|
1878
|
+
|
|
1879
|
+
if self.score_thr is not None:
|
|
1880
|
+
keep = probability>self.score_thr
|
|
1881
|
+
labels = labels[keep]
|
|
1882
|
+
boxes = boxes[keep]
|
|
1883
|
+
probability = probability[keep]
|
|
1884
|
+
|
|
1885
|
+
tmp_pred_labels = []
|
|
1886
|
+
tmp_gt_labels = []
|
|
1887
|
+
gt_set = set(list(range(gtlabels.shape[0])))
|
|
1888
|
+
pred_set = set(list(range(labels.shape[0])))
|
|
1889
|
+
|
|
1890
|
+
if len(gt_set)>0 and len(pred_set)>0:
|
|
1891
|
+
iou_matrix = odb.iou_matrix(boxes,gtboxes) #boxes_nr x gtboxes_nr
|
|
1892
|
+
max_idx = np.argmax(iou_matrix,axis=0)
|
|
1893
|
+
ious = np.max(iou_matrix,axis=0)
|
|
1894
|
+
|
|
1895
|
+
sorted_idx = np.argsort(ious)[::-1]
|
|
1896
|
+
|
|
1897
|
+
for gt_idx in sorted_idx:
|
|
1898
|
+
iou = ious[gt_idx]
|
|
1899
|
+
if iou<self.iou_thr:
|
|
1900
|
+
break
|
|
1901
|
+
pred_idx = max_idx[gt_idx]
|
|
1902
|
+
if pred_idx not in pred_set:
|
|
1903
|
+
continue
|
|
1904
|
+
tmp_gt_labels.append(gtlabels[gt_idx])
|
|
1905
|
+
tmp_pred_labels.append(labels[pred_idx])
|
|
1906
|
+
gt_set.remove(gt_idx)
|
|
1907
|
+
pred_set.remove(pred_idx)
|
|
1908
|
+
|
|
1909
|
+
for idx in gt_set:
|
|
1910
|
+
v = gtlabels[idx]
|
|
1911
|
+
tmp_gt_labels.append(v)
|
|
1912
|
+
tmp_pred_labels.append(self.num_classes) #使用self.num_classes+1作为背景
|
|
1913
|
+
|
|
1914
|
+
for idx in pred_set:
|
|
1915
|
+
v = labels[idx]
|
|
1916
|
+
tmp_gt_labels.append(self.num_classes)
|
|
1917
|
+
tmp_pred_labels.append(v)
|
|
1918
|
+
|
|
1919
|
+
self.pred_labels.extend(tmp_pred_labels)
|
|
1920
|
+
self.gt_labels.extend(tmp_gt_labels)
|
|
1921
|
+
self.image_id += 1
|
|
1922
|
+
#self.show()
|
|
1923
|
+
|
|
1924
|
+
def evaluate(self):
|
|
1925
|
+
print(f"Test size {self.num_examples()}")
|
|
1926
|
+
self.kernel(output=np.array(self.pred_labels,dtype=np.int32),
|
|
1927
|
+
target=np.array(self.gt_labels,dtype=np.int32))
|
|
1928
|
+
self.kernel.evaluate()
|
|
1929
|
+
|
|
1930
|
+
def show(self,name=""):
|
|
1931
|
+
#显示的最后一行,列为背景
|
|
1932
|
+
'''
|
|
1933
|
+
i行,j列: 表示gt类别i被分为类别j的数量
|
|
1934
|
+
'''
|
|
1935
|
+
sys.stdout.flush()
|
|
1936
|
+
print(f"Test size {self.num_examples()}")
|
|
1937
|
+
self.evaluate()
|
|
1938
|
+
return self.kernel.show()
|
|
1939
|
+
|
|
1940
|
+
def to_string(self):
|
|
1941
|
+
return self.kernel.to_string()
|
|
1942
|
+
|
|
1943
|
+
def __repr__(self):
|
|
1944
|
+
return self.to_string()
|
|
1945
|
+
|
|
1946
|
+
def value(self):
|
|
1947
|
+
return self.kernel.value()
|
|
1948
|
+
|
|
1949
|
+
def num_examples(self):
|
|
1950
|
+
return self.image_id
|
|
1951
|
+
|
|
1952
|
+
|
|
1953
|
+
|