-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpush_annotations.py
177 lines (144 loc) · 7.11 KB
/
push_annotations.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import os
import shutil
import argparse
import requests
import pandas as pd
from tqdm import tqdm
from biigle.biigle import Api
# Example:
# python push_annotations.py -e [email protected] -t SVRTBSUtVcQXZHjkNOxI29Zg2yu0nuhw -i 839 -d C:\Users\cgros\Documents\BIIGLE_library\TO_BE_UPLOADED -l 178966
def get_parser():
parser = argparse.ArgumentParser(add_help=False)
# MANDATORY ARGUMENTS
mandatory_args = parser.add_argument_group('MANDATORY ARGUMENTS')
mandatory_args.add_argument('-e', '--email', required=True, type=str,
help='Email address used for BIIGLE account.')
mandatory_args.add_argument('-t', '--token', required=True, type=str,
help='BIIGLE API token. To generate one: https://biigle.de/settings/tokens')
mandatory_args.add_argument('-i', '--label-tree-id', dest='label_tree_id', required=True, type=int,
help='Label tree ID.')
mandatory_args.add_argument('-d', '--datafolder', required=True, type=str,
help='Data folder.')
mandatory_args.add_argument('-o', '--ofname', required=True, type=str,
help='CSV filename to save old annotations.')
# OPTIONAL ARGUMENTS
optional_args = parser.add_argument_group('OPTIONAL ARGUMENTS')
optional_args.add_argument('-l', '--label-id', dest='label_id', required=False, type=int,
help='Label ID to push. If indicated, only patches from this label are pushed. '
'Otherwise, all patches are pushed. You can find the ID of a label in the JSON '
'output of the label tree, eg https://biigle.de/api/v1/label-trees/1, by replacing '
'"1" by the ID of your label-tree of interest.')
optional_args.add_argument('-c', '--csv-done', dest='excel_done', required=False, type=str,
help='Excel used to track the changes between old and new tree. CSV file')
optional_args.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS,
help='Shows function documentation.')
return parser
def get_label_info(labels, label_id):
for label in labels:
if label["id"] == label_id:
return label
print("Label ID not found: {}.".format(label_id))
return
def get_label_name(labels, label_id):
label_info = get_label_info(labels, label_id)
label_name = label_info["name"]
if not label_info["parent_id"] is None:
parent_info = get_label_info(labels, label_info["parent_id"])
parent_name = parent_info["name"]
label_name = parent_name + "_" + label_name
return label_name
def get_survey(surveys, survey_name):
for survey in surveys:
if survey["name"] == survey_name:
return survey
print("Survey not found: {}.".format(survey_name))
return
def add_parent_name(label_tree_info, labels_info_list):
id_of_interest = [l['id'] for l in label_tree_info]
out_list = []
for label_info in labels_info_list:
# Discard
if not label_info['id'] in id_of_interest:
continue
parent_info = [label_tree_info_ for label_tree_info_ in label_tree_info
if label_tree_info_['id'] == label_info['parent_id']]
if len(parent_info) == 0: # No parent
parent_name = ''
elif len(parent_info) == 1:
parent_name = parent_info[0]['name']
else:
print('ERROR: multiple parents: {}.'.format(label_info))
exit()
label_info['parent_name'] = parent_name
out_list.append(label_info)
return out_list
def push_patches(email, token, fname_excel_done, datafolder, label_tree_id, fname_o, label_id=None):
# Init API
api = Api(email, token)
# Init excel_done
if fname_excel_done is None:
excel_done = {"done": [], "error": []}
print("No tracking excel provided, starting from scratch.")
else:
df = pd.read_csv(fname_excel_done)
excel_done = {"done": df["done"].values.tolist(),
"error": df["error"].values.tolist()}
# Get label info
label_tree_info = api.get('label-trees/{}'.format(label_tree_id)).json()
#labels_info_list = add_parent_name(label_tree_info['labels'], labels_info_list)
# Get new labels
lst_label_new = label_tree_info["labels"]
if not label_id is None:
lst_label_new = [l for l in lst_label_new if l["id"] == label_id]
#if label_id is None:
# lst_label_new = [l for l in os.listdir(datafolder) if os.path.isdir(os.path.join(datafolder, l))]
#else:
# lst_label_new = [get_label_name(label_tree_info["labels"], label_id)]
print(lst_label_new)
# Loop across new labels
for label_new in lst_label_new:
name_label_new = get_label_name(label_tree_info["labels"], label_new["id"])
print("\n" + name_label_new)
folder_label = os.path.join(datafolder, name_label_new)
if os.path.isdir(folder_label):
lst_annotations = [a.split(".")[0] for a in os.listdir(folder_label)
if os.path.isfile(os.path.join(folder_label, a)) and a.endswith(".jpg")]
lst_annotations = [a for a in lst_annotations if int(a) not in excel_done["done"] and int(a) not in excel_done["error"]]
if len(lst_annotations):
# Loop across annotations
for id_annotation_old in tqdm(lst_annotations):
try:
info_annotation_old = api.get('image-annotations/{}'.format(int(id_annotation_old))).json()
info_annotation_new = {
"image_id": info_annotation_old["image_id"],
"shape_id": info_annotation_old["shape_id"],
"label_id": label_new["id"],
"confidence": 1.00,
"points": info_annotation_old["points"]
}
api.post("image-annotations", json=[info_annotation_new])
excel_done["done"].append(id_annotation_old)
excel_done["error"].append(None)
except:
excel_done["error"].append(id_annotation_old)
excel_done["done"].append(None)
df_done = pd.DataFrame.from_dict(excel_done)
df_done.to_csv(fname_o, index=False)
print("\nSaving done annotations...")
df_done = pd.DataFrame.from_dict(excel_done)
df_done.to_csv(fname_o, index=False)
exit()
print('\n\n---------- Finished ----------\n\n')
def main():
parser = get_parser()
args = parser.parse_args()
# Run function
push_patches(email=args.email,
token=args.token,
datafolder=args.datafolder,
fname_excel_done=args.excel_done,
label_tree_id=args.label_tree_id,
fname_o=args.ofname,
label_id=args.label_id)
if __name__ == "__main__":
main()