Merge and translate ground_truth_file
or predictions
to ground_truth
's old_images
coordinates.
Parameters:
Name |
Type |
Description |
Default |
ground_truth_file |
str
|
Path to COCO ground truth file of crops. Generated with
crops_split . |
required
|
output_file |
str
|
Path where the merged annotations will be saved. |
required
|
predictions_file |
Optional[str]
|
Path to COCO predictions file over ground_truth_file .
If not None, the annotations of predictions_file will be merged instead of ground_truth_file's. |
None
|
apply_nms |
bool
|
Whether to apply Non Maximum Supression to the merged predictions of
each image. Defaults to True. |
True
|
score_thr |
float
|
Predictions bellow score_thr will be filtered. Only used if
apply_nms . Defaults to 0.0. |
0.0
|
iou_thr |
float
|
None of the filtered predictions will have an iou above iou_thr to
any other. Only used if apply_nms . Defaults to 0.5. |
0.5
|
Source code in pyodi/apps/crops/crops_merge.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 | @logger.catch(reraise=True)
def crops_merge(
ground_truth_file: str,
output_file: str,
predictions_file: Optional[str] = None,
apply_nms: bool = True,
score_thr: float = 0.0,
iou_thr: float = 0.5,
) -> str:
"""Merge and translate `ground_truth_file` or `predictions` to `ground_truth`'s `old_images` coordinates.
Args:
ground_truth_file: Path to COCO ground truth file of crops. Generated with
`crops_split`.
output_file: Path where the merged annotations will be saved.
predictions_file: Path to COCO predictions file over `ground_truth_file`.
If not None, the annotations of predictions_file will be merged instead of ground_truth_file's.
apply_nms: Whether to apply Non Maximum Supression to the merged predictions of
each image. Defaults to True.
score_thr: Predictions bellow `score_thr` will be filtered. Only used if
`apply_nms`. Defaults to 0.0.
iou_thr: None of the filtered predictions will have an iou above `iou_thr` to
any other. Only used if `apply_nms`. Defaults to 0.5.
"""
ground_truth = json.load(open(ground_truth_file))
crop_id_to_filename = {x["id"]: x["file_name"] for x in ground_truth["images"]}
stem_to_original_id = {
Path(x["file_name"]).stem: x["id"] for x in ground_truth["old_images"]
}
stem_to_original_shape = {
Path(x["file_name"]).stem: (x["width"], x["height"])
for x in ground_truth["old_images"]
}
if predictions_file is not None:
annotations = json.load(open(predictions_file))
else:
annotations = ground_truth["annotations"]
for n, crop in enumerate(annotations):
if not n % 10:
logger.info(n)
filename = crop_id_to_filename[crop["image_id"]]
parts = Path(filename).stem.split("_")
stem = "_".join(parts[:-2])
original_id = stem_to_original_id[stem]
crop["image_id"] = original_id
# Corners are encoded in crop's filename
# See crops_split.py
crop_row = int(parts[-1])
crop_col = int(parts[-2])
crop["bbox"][0] += crop_col
crop["bbox"][1] += crop_row
crop["original_image_shape"] = stem_to_original_shape[stem]
if apply_nms:
annotations = nms_predictions(annotations, score_thr=score_thr, iou_thr=iou_thr)
output_file = str(
Path(output_file).parent
/ f"{Path(output_file).stem}_{score_thr}_{iou_thr}.json"
)
if predictions_file is not None:
new_ground_truth = annotations
else:
new_ground_truth = {
"info": ground_truth.get("info", []),
"licenses": ground_truth.get("licenses", []),
"categories": ground_truth.get("categories", []),
"images": ground_truth.get("old_images"),
"annotations": annotations,
}
with open(output_file, "w") as f:
json.dump(new_ground_truth, f, indent=2)
return output_file
|