Skip to content

Commit 1d1e4b4

Browse files
authored
Merge pull request #43 from swiss-territorial-data-lab/gs/make_examples
Debug metrics
2 parents 298492f + 323bc0c commit 1d1e4b4

File tree

3 files changed

+38
-52
lines changed

3 files changed

+38
-52
lines changed

helpers/metrics.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,7 @@ def get_metrics(tp_gdf, fp_gdf, fn_gdf, mismatch_gdf, id_classes=0, method='macr
150150
pw_k = by_class_dict.copy()
151151
rw_k = by_class_dict.copy()
152152

153-
by_class_dict = {key: None for key in id_classes}
154-
tp_k = by_class_dict.copy()
155-
fp_k = by_class_dict.copy()
156-
fn_k = by_class_dict.copy()
157-
p_k = by_class_dict.copy()
158-
r_k = by_class_dict.copy()
159-
count_k = by_class_dict.copy()
160-
pw_k = by_class_dict.copy()
161-
rw_k = by_class_dict.copy()
153+
total_labels = len(tp_gdf) + len(fn_gdf) + len(mismatch_gdf)
162154

163155
for id_cl in id_classes:
164156

@@ -176,25 +168,27 @@ def get_metrics(tp_gdf, fp_gdf, fn_gdf, mismatch_gdf, id_classes=0, method='macr
176168
fn_count = pure_fn_count + mismatched_fn_count
177169
tp_count = 0 if tp_gdf.empty else len(tp_gdf[tp_gdf.det_class==id_cl])
178170

179-
tp_k[id_cl] = tp_count
180171
fp_k[id_cl] = fp_count
181172
fn_k[id_cl] = fn_count
182-
183-
p_k[id_cl] = 0 if tp_count == 0 else tp_count / (tp_count + fp_count)
184-
r_k[id_cl] = 0 if tp_count == 0 else tp_count / (tp_count + fn_count)
185-
count_k[id_cl] = 0 if tp_count == 0 else tp_count + fn_count
173+
tp_k[id_cl] = tp_count
174+
175+
count_k[id_cl] = tp_count + fn_count
176+
if tp_count > 0:
177+
p_k[id_cl] = tp_count / (tp_count + fp_count)
178+
r_k[id_cl] = tp_count / (tp_count + fn_count)
179+
180+
if (method == 'macro-weighted-average') & (total_labels > 0):
181+
pw_k[id_cl] = (count_k[id_cl] / total_labels) * p_k[id_cl]
182+
rw_k[id_cl] = (count_k[id_cl] / total_labels) * r_k[id_cl]
186183

187184
if method == 'macro-average':
188185
precision = sum(p_k.values()) / len(id_classes)
189186
recall = sum(r_k.values()) / len(id_classes)
190-
elif method == 'macro-weighted-average':
191-
for id_cl in id_classes:
192-
pw_k[id_cl] = 0 if sum(count_k.values()) == 0 else (count_k[id_cl] / sum(count_k.values())) * p_k[id_cl]
193-
rw_k[id_cl] = 0 if sum(count_k.values()) == 0 else (count_k[id_cl] / sum(count_k.values())) * r_k[id_cl]
187+
elif method == 'macro-weighted-average':
194188
precision = sum(pw_k.values()) / len(id_classes)
195189
recall = sum(rw_k.values()) / len(id_classes)
196190
elif method == 'micro-average':
197-
if sum(tp_k.values()) == 0 and sum(fp_k.values()) == 0:
191+
if sum(tp_k.values()) == 0:
198192
precision = 0
199193
recall = 0
200194
else:
@@ -224,4 +218,9 @@ def intersection_over_union(polygon1_shape, polygon2_shape):
224218
polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
225219
polygon_union = polygon1_shape.area + polygon2_shape.area - polygon_intersection
226220

227-
return polygon_intersection / polygon_union
221+
if polygon_union != 0:
222+
iou = polygon_intersection / polygon_union
223+
else:
224+
iou = 0
225+
226+
return iou

helpers/misc.py

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
from shapely.validation import make_valid
1717
from rasterio.transform import from_bounds
1818

19+
try:
20+
try:
21+
from helpers.metrics import intersection_over_union
22+
except ModuleNotFoundError:
23+
from metrics import intersection_over_union
24+
except Exception as e:
25+
logger.error(f"Could not import some dependencies. Exception: {e}")
26+
sys.exit(1)
27+
1928

2029
class BadFileExtensionException(Exception):
2130
"Raised when the file extension is different from the expected one"
@@ -144,29 +153,6 @@ def clip_row(row, fact=fact):
144153
return clipped_labels_gdf
145154

146155

147-
def intersection_over_union(polygon1_shape, polygon2_shape):
148-
"""Determine the intersection area over union area (IoU) of two polygons
149-
150-
Args:
151-
polygon1_shape (geometry): first polygon
152-
polygon2_shape (geometry): second polygon
153-
154-
Returns:
155-
int: Unrounded ratio between the intersection and union area
156-
"""
157-
158-
# Calculate intersection and union, and the IoU
159-
polygon_intersection = polygon1_shape.intersection(polygon2_shape).area
160-
polygon_union = polygon1_shape.area + polygon2_shape.area - polygon_intersection
161-
162-
if polygon_union != 0:
163-
iou = polygon_intersection / polygon_union
164-
else:
165-
iou = 0
166-
167-
return iou
168-
169-
170156
def format_logger(logger):
171157

172158
logger.remove()

scripts/make_detections.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def main(cfg_file_path):
6262
DETECTRON2_CFG_FILE = cfg['detectron2_config_file']
6363

6464
WORKING_DIR = cfg['working_directory']
65+
OUTPUT_DIR = cfg['output_folder'] if 'output_folder' in cfg.keys() else '.'
6566
SAMPLE_TAGGED_IMG_SUBDIR = cfg['sample_tagged_img_subfolder']
6667
LOG_SUBDIR = cfg['log_subfolder']
6768

@@ -74,9 +75,8 @@ def main(cfg_file_path):
7475

7576
os.chdir(WORKING_DIR)
7677
# let's make the output directories in case they don't exist
77-
for DIR in [SAMPLE_TAGGED_IMG_SUBDIR, LOG_SUBDIR]:
78-
if not os.path.exists(DIR):
79-
os.makedirs(DIR)
78+
for directory in [OUTPUT_DIR, SAMPLE_TAGGED_IMG_SUBDIR, LOG_SUBDIR]:
79+
os.makedirs(directory, exist_ok=True)
8080

8181
written_files = []
8282

@@ -121,7 +121,7 @@ def main(cfg_file_path):
121121

122122
logger.info(f"Making detections over the entire {dataset} dataset...")
123123

124-
detections_filename = f'{dataset}_detections_at_{threshold_str}_threshold.gpkg'
124+
detections_filename = os.path.join(OUTPUT_DIR, f'{dataset}_detections_at_{threshold_str}_threshold.gpkg')
125125

126126
for d in tqdm(DatasetCatalog.get(dataset)):
127127

@@ -181,13 +181,14 @@ def main(cfg_file_path):
181181
im = cv2.imread(d["file_name"])
182182
outputs = predictor(im)
183183
v = Visualizer(im[:, :, ::-1], # [:, :, ::-1] is for RGB -> BGR conversion, cf. https://stackoverflow.com/questions/14556545/why-opencv-using-bgr-colour-space-instead-of-rgb
184-
metadata=MetadataCatalog.get(dataset),
185-
scale=1.0,
186-
instance_mode=ColorMode.IMAGE_BW # remove the colors of unsegmented pixels
184+
metadata=MetadataCatalog.get(dataset),
185+
scale=1.0,
186+
instance_mode=ColorMode.IMAGE_BW # remove the colors of unsegmented pixels
187187
)
188188
v = v.draw_instance_predictions(outputs["instances"].to("cpu"))
189-
cv2.imwrite(os.path.join(SAMPLE_TAGGED_IMG_SUBDIR, output_filename), v.get_image()[:, :, ::-1])
190-
written_files.append(os.path.join(WORKING_DIR, SAMPLE_TAGGED_IMG_SUBDIR, output_filename))
189+
filepath = os.path.join(SAMPLE_TAGGED_IMG_SUBDIR, output_filename)
190+
cv2.imwrite(filepath, v.get_image()[:, :, ::-1])
191+
written_files.append(os.path.join(WORKING_DIR, filepath))
191192
logger.success(DONE_MSG)
192193

193194

0 commit comments

Comments
 (0)