Skip to content

Commit b59203a

Browse files
committed
Fix dataframe to json output
1 parent 7b7d747 commit b59203a

File tree

4 files changed

+123
-96
lines changed

4 files changed

+123
-96
lines changed

superannotate/analytics/common.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,16 @@ def df_to_annotations(df, output_dir):
2424
project_suffix = "objects.json"
2525
images = df["imageName"].dropna().unique()
2626
for image in images:
27+
image_status = None
28+
image_pinned = None
29+
image_height = None
30+
image_width = None
2731
image_df = df[df["imageName"] == image]
2832
image_annotation = []
2933
instances = image_df["instanceId"].dropna().unique()
3034
for instance in instances:
3135
instance_df = image_df[image_df["instanceId"] == instance]
36+
# print(instance_df["instanceId"])
3237
annotation_type = instance_df.iloc[0]["type"]
3338
annotation_meta = instance_df.iloc[0]["meta"]
3439

@@ -60,6 +65,10 @@ def df_to_annotations(df, output_dir):
6065
}
6166
)
6267
image_annotation.append(instance_annotation)
68+
image_width = image_width or instance_df.iloc[0]["imageWidth"]
69+
image_height = image_height or instance_df.iloc[0]["imageHeight"]
70+
image_pinned = image_pinned or instance_df.iloc[0]["imagePinned"]
71+
image_status = image_status or instance_df.iloc[0]["imageStatus"]
6372

6473
comments = image_df[image_df["type"] == "comment"]
6574
for _, comment in comments.iterrows():
@@ -68,6 +77,14 @@ def df_to_annotations(df, output_dir):
6877
comment_json["resolved"] = comment["commentResolved"]
6978
image_annotation.append(comment_json)
7079

80+
meta = {
81+
"type": "meta",
82+
"width": int(image_width),
83+
"height": int(image_height),
84+
"status": image_status,
85+
"pinned": bool(image_pinned)
86+
}
87+
image_annotation.append(meta)
7188
json.dump(
7289
image_annotation,
7390
open(output_dir / f"{image}___{project_suffix}", "w"),
@@ -232,7 +249,7 @@ def __get_user_metadata(annotation):
232249
if annotation_updated_by:
233250
annotation_updator_email = annotation_updated_by.get("email")
234251
annotation_updator_role = annotation_updated_by.get("role")
235-
user_metadata = {
252+
user_metadata = {
236253
"createdAt": annotation_created_at,
237254
"creatorRole": annotation_creator_role,
238255
"creatorEmail": annotation_creator_email,
@@ -242,17 +259,19 @@ def __get_user_metadata(annotation):
242259
"updatorEmail": annotation_updator_email
243260
}
244261
return user_metadata
245-
262+
246263
annotations_paths = []
247-
264+
248265
for path in Path(project_root).glob('*.json'):
249266
annotations_paths.append(path)
250267

251268
if not annotations_paths:
252269
logger.warning(
253270
"No annotations found in project export root %s", project_root
254271
)
255-
type_postfix = "___objects.json" if glob.glob("{}/*___objects.json".format(project_root)) else "___pixel.json"
272+
type_postfix = "___objects.json" if glob.glob(
273+
"{}/*___objects.json".format(project_root)
274+
) else "___pixel.json"
256275
for annotation_path in annotations_paths:
257276
annotation_json = json.load(open(annotation_path))
258277
image_name = annotation_path.name.split(type_postfix)[0]
@@ -290,7 +309,6 @@ def __get_user_metadata(annotation):
290309
annotation_dict.update(image_metadata)
291310
__append_annotation(annotation_dict)
292311
continue
293-
annotation_instance_id += 1
294312
annotation_class_name = annotation.get("className")
295313
if annotation_class_name is None or annotation_class_name not in class_name_to_color:
296314
logger.warning(
@@ -328,6 +346,7 @@ def __get_user_metadata(annotation):
328346
annotation_point_labels = annotation.get("pointLabels")
329347
attributes = annotation.get("attributes")
330348
user_metadata = __get_user_metadata(annotation)
349+
num_added = 0
331350
if not attributes:
332351
annotation_dict = {
333352
"imageName": image_name,
@@ -347,6 +366,7 @@ def __get_user_metadata(annotation):
347366
annotation_dict.update(user_metadata)
348367
annotation_dict.update(image_metadata)
349368
__append_annotation(annotation_dict)
369+
num_added = 1
350370
else:
351371
for attribute in attributes:
352372
attribute_group = attribute.get("groupName")
@@ -385,6 +405,10 @@ def __get_user_metadata(annotation):
385405
annotation_dict.update(user_metadata)
386406
annotation_dict.update(image_metadata)
387407
__append_annotation(annotation_dict)
408+
num_added += 1
409+
410+
if num_added > 0:
411+
annotation_instance_id += 1
388412

389413
df = pd.DataFrame(annotation_data)
390414

superannotate/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.4.0"
1+
__version__ = "2.4.1"

tests/test_create_from_full_info.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
from pathlib import Path
2-
31
import superannotate as sa
42

5-
import pytest
6-
73
PROJECT_NAME1 = "test create from full info1"
84
PROJECT_NAME2 = "test create from full info2"
95

106

11-
def test_create_from_full_info(tmpdir):
12-
tmpdir = Path(tmpdir)
13-
7+
def test_create_from_full_info():
148
projects = sa.search_projects(PROJECT_NAME1, return_metadata=True)
159
for project in projects:
1610
sa.delete_project(project)
@@ -27,7 +21,7 @@ def test_create_from_full_info(tmpdir):
2721
for setting in old_settings:
2822
if "attribute" in setting and setting["attribute"] == "Brightness":
2923
brightness_value = setting["value"]
30-
new_settings = sa.set_project_settings(
24+
sa.set_project_settings(
3125
PROJECT_NAME1,
3226
[{
3327
"attribute": "Brightness",

tests/test_filter_instances.py

Lines changed: 91 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -173,85 +173,94 @@ def test_filter_instances(tmpdir):
173173
# print(not_filtered[not_filtered["className"] == "Human
174174

175175

176-
# def test_df_to_annotations(tmpdir):
177-
# tmpdir = Path(tmpdir)
178-
179-
# df = sa.aggregate_annotations_as_df(PROJECT_DIR)
180-
# sa.df_to_annotations(df, tmpdir)
181-
# df_new = sa.aggregate_annotations_as_df(tmpdir)
182-
183-
# print(df_new["imageName"].value_counts())
184-
# print(df["imageName"].value_counts())
185-
186-
# for _index, row in enumerate(df.iterrows()):
187-
# for _, row_2 in enumerate(df_new.iterrows()):
188-
# if row_2[1].equals(row[1]):
189-
# break
190-
# else:
191-
# assert False
192-
# for project in sa.search_projects("test df to annotations 2"):
193-
# sa.delete_project(project)
194-
# project = sa.create_project("test df to annotations 2", "test", "Vector")
195-
# sa.upload_images_from_folder_to_project(
196-
# project, "./tests/sample_project_vector"
197-
# )
198-
# sa.create_annotation_classes_from_classes_json(
199-
# project, "./tests/sample_project_vector/classes/classes.json"
200-
# )
201-
# sa.upload_annotations_from_folder_to_project(
202-
# project, "./tests/sample_project_vector"
203-
# )
204-
205-
# def test_df_to_annotations_full(tmpdir):
206-
# tmpdir = Path(tmpdir)
207-
208-
# df = sa.aggregate_annotations_as_df(
209-
# PROJECT_DIR, include_classes_wo_annotations=True, include_comments=True
210-
# )
211-
# sa.df_to_annotations(df, tmpdir)
212-
# df_new = sa.aggregate_annotations_as_df(
213-
# tmpdir, include_classes_wo_annotations=True, include_comments=True
214-
# )
215-
# for project in sa.search_projects("test df to annotations 4"):
216-
# sa.delete_project(project)
217-
# project = sa.create_project("test df to annotations 4", "test", "Vector")
218-
# sa.upload_images_from_folder_to_project(project, PROJECT_DIR)
219-
# sa.create_annotation_classes_from_classes_json(
220-
# project, tmpdir / "classes" / "classes.json"
221-
# )
222-
# sa.upload_annotations_from_folder_to_project(project, tmpdir)
223-
# # print(df_new["image_name"].value_counts())
224-
# # print(df["image_name"].value_counts())
225-
# for _index, row in enumerate(df.iterrows()):
226-
# for _, row_2 in enumerate(df_new.iterrows()):
227-
# if row_2[1].equals(row[1]):
228-
# break
229-
# else:
230-
# assert False
231-
232-
# fil1 = sa.filter_annotation_instances(
233-
# df_new,
234-
# include=[
235-
# {
236-
# "className": "Personal vehicle",
237-
# "attributes": [{
238-
# "name": "4",
239-
# "groupName": "Num doors"
240-
# }]
241-
# }
242-
# ],
243-
# exclude=[{
244-
# "type": "polygon"
245-
# }]
246-
# )
247-
# filtered_export = (tmpdir / "filtered")
248-
# filtered_export.mkdir()
249-
# sa.df_to_annotations(fil1, filtered_export)
250-
# for project in sa.search_projects("test df to annotations 3"):
251-
# sa.delete_project(project)
252-
# project = sa.create_project("test df to annotations 3", "test", "Vector")
253-
# sa.upload_images_from_folder_to_project(project, PROJECT_DIR)
254-
# sa.create_annotation_classes_from_classes_json(
255-
# project, filtered_export / "classes" / "classes.json"
256-
# )
257-
# sa.upload_annotations_from_folder_to_project(project, filtered_export)
176+
def test_df_to_annotations(tmpdir):
177+
tmpdir = Path(tmpdir)
178+
179+
df = sa.aggregate_annotations_as_df(PROJECT_DIR)
180+
sa.df_to_annotations(df, tmpdir)
181+
df_new = sa.aggregate_annotations_as_df(tmpdir)
182+
183+
assert len(df) == len(df_new)
184+
# print(df_new["imageName"].value_counts())
185+
# print(df["imageName"].value_counts())
186+
# print(len(df.columns))
187+
# print(len(df_new.columns))
188+
189+
# print(df[df["imageName"] == "example_image_1.jpg"]["instanceId"])
190+
# print(df_new[(df_new["imageName"] == "example_image_1.jpg")]["instanceId"])
191+
for _index, row in enumerate(df.iterrows()):
192+
for _, row_2 in enumerate(df_new.iterrows()):
193+
if row_2[1].equals(row[1]):
194+
break
195+
# if row_2[1]["imageName"] == "example_image_1.jpg":
196+
# print(row_2[1])
197+
else:
198+
assert False, print("Error on ", row[1])
199+
200+
for project in sa.search_projects("test df to annotations 2"):
201+
sa.delete_project(project)
202+
project = sa.create_project("test df to annotations 2", "test", "Vector")
203+
sa.upload_images_from_folder_to_project(
204+
project, "./tests/sample_project_vector"
205+
)
206+
sa.create_annotation_classes_from_classes_json(
207+
project, "./tests/sample_project_vector/classes/classes.json"
208+
)
209+
sa.upload_annotations_from_folder_to_project(
210+
project, "./tests/sample_project_vector"
211+
)
212+
213+
214+
def test_df_to_annotations_full(tmpdir):
215+
tmpdir = Path(tmpdir)
216+
217+
df = sa.aggregate_annotations_as_df(
218+
PROJECT_DIR, include_classes_wo_annotations=True, include_comments=True
219+
)
220+
sa.df_to_annotations(df, tmpdir)
221+
df_new = sa.aggregate_annotations_as_df(
222+
tmpdir, include_classes_wo_annotations=True, include_comments=True
223+
)
224+
for project in sa.search_projects("test df to annotations 4"):
225+
sa.delete_project(project)
226+
project = sa.create_project("test df to annotations 4", "test", "Vector")
227+
sa.upload_images_from_folder_to_project(project, PROJECT_DIR)
228+
sa.create_annotation_classes_from_classes_json(
229+
project, tmpdir / "classes" / "classes.json"
230+
)
231+
sa.upload_annotations_from_folder_to_project(project, tmpdir)
232+
# print(df_new["image_name"].value_counts())
233+
# print(df["image_name"].value_counts())
234+
for _index, row in enumerate(df.iterrows()):
235+
for _, row_2 in enumerate(df_new.iterrows()):
236+
if row_2[1].equals(row[1]):
237+
break
238+
else:
239+
assert False
240+
241+
fil1 = sa.filter_annotation_instances(
242+
df_new,
243+
include=[
244+
{
245+
"className": "Personal vehicle",
246+
"attributes": [{
247+
"name": "4",
248+
"groupName": "Num doors"
249+
}]
250+
}
251+
],
252+
exclude=[{
253+
"type": "polygon"
254+
}]
255+
)
256+
filtered_export = (tmpdir / "filtered")
257+
filtered_export.mkdir()
258+
sa.df_to_annotations(fil1, filtered_export)
259+
for project in sa.search_projects("test df to annotations 3"):
260+
sa.delete_project(project)
261+
project = sa.create_project("test df to annotations 3", "test", "Vector")
262+
sa.upload_images_from_folder_to_project(project, PROJECT_DIR)
263+
sa.create_annotation_classes_from_classes_json(
264+
project, filtered_export / "classes" / "classes.json"
265+
)
266+
sa.upload_annotations_from_folder_to_project(project, filtered_export)

0 commit comments

Comments
 (0)