Skip to content

Commit 2853a9b

Browse files
committed
2 parents a5d94a6 + 5f82171 commit 2853a9b

16 files changed

+546
-111
lines changed

docs/source/cli.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,38 @@ scanned for available images.
5252

5353
Optional argument *extensions* accepts comma separated list of image extensions to look for. If the argument is not given then value *jpg,png* is assumed.
5454

55+
----------
56+
57+
.. _ref_upload_videos:
58+
59+
Uploading videos
60+
~~~~~~~~~~~~~~~~
61+
62+
To upload videos from folder to project use:
63+
64+
.. code-block:: bash
65+
66+
superannotate upload-videos --project <project_name> --folder <folder_path>
67+
[--recursive] [--extensions mp4,avi,mov,webm,flv,mpg,ogg]
68+
[--target-fps <float>] [--start-time <float>]
69+
[--end-time <float>]
70+
71+
If optional argument *recursive* is given then subfolders of :file:`<folder_path>` are also recursively
72+
scanned for available images.
73+
74+
Optional argument *extensions* accepts comma separated list of image extensions
75+
to look for. If the argument is not given then value *mp4,avi,mov,webm,flv,mpg,ogg* is assumed.
76+
77+
*target-fps* specifies how many frames per second need to extract from the videos (approximate).
78+
If not specified all frames will be uploaded.
79+
80+
*start-time* specifies time (in seconds) from which to start extracting frames,
81+
default is 0.0.
82+
83+
*end-time* specifies time (in seconds) up to which to extract frames.
84+
If it is not specified, then up to end is assumed.
85+
86+
5587
----------
5688

5789
.. _ref_cli_version:

docs/source/superannotate.sdk.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ ________
4242
.. autofunction:: superannotate.unshare_project
4343
.. autofunction:: superannotate.get_project_settings
4444
.. autofunction:: superannotate.set_project_settings
45+
.. autofunction:: superannotate.get_project_default_image_quality_in_editor
46+
.. autofunction:: superannotate.set_project_default_image_quality_in_editor
4547
.. autofunction:: superannotate.get_project_workflow
4648
.. autofunction:: superannotate.set_project_workflow
4749

@@ -74,6 +76,8 @@ ______
7476
.. autofunction:: superannotate.upload_annotations_from_json_to_image
7577
.. autofunction:: superannotate.copy_image
7678
.. autofunction:: superannotate.move_image
79+
.. autofunction:: superannotate.pin_image
80+
.. autofunction:: superannotate.assign_images
7781
.. autofunction:: superannotate.delete_image
7882
.. autofunction:: superannotate.add_annotation_bbox_to_image
7983
.. autofunction:: superannotate.add_annotation_polygon_to_image

docs/source/tutorial.sdk.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,8 @@ Grassroots DICOM library <http://gdcm.sourceforge.net/wiki/index.php/Main_Page>`
502502
----------
503503

504504

505-
Computing consensus scores for instancec between several projects
506-
_______________________________________________________
505+
Computing consensus scores for instances between several projects
506+
_________________________________________________________________
507507

508508

509509
Consensus is a tool to compare the quallity of the annotations of the same image that is present in several projects.

install.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/bin/bash
22

3-
PYTHON_VER="3.6"
3+
PYTHON_VER="3.7"
44

55
# ubuntu install dependencies
6-
# sudo add-apt-repository ppa:deadsnakes/ppa
7-
# sudo apt update
8-
# sudo apt install python${PYTHON_VER} python${PYTHON_VER}-venv python${PYTHON_VER}-dev
6+
sudo add-apt-repository ppa:deadsnakes/ppa
7+
sudo apt update
8+
sudo apt install python${PYTHON_VER} python${PYTHON_VER}-venv python${PYTHON_VER}-dev
99

1010
rm -rf venv_sa_conv
1111
python${PYTHON_VER} -m venv venv_sa_conv
@@ -16,3 +16,12 @@ pip install 'git+https://github.com/cocodataset/panopticapi.git'
1616
pip install 'git+https://github.com/philferriere/cocoapi.git#egg=pycocotools&subdirectory=PythonAPI'
1717

1818
pip install -e .
19+
20+
# for testing
21+
pip install pytest pytest-xdist
22+
23+
# for docs
24+
pip install sphinx sphinx_rtd_theme
25+
26+
# for pip
27+
pip install twine

superannotate/__init__.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
image_path_to_annotation_paths, project_type_int_to_str,
2222
project_type_str_to_int, user_role_str_to_int
2323
)
24+
from .consensus_benchmark.consensus import consensus
2425
from .dataframe_filtering import (
2526
filter_annotation_instances, filter_images_by_comments,
2627
filter_images_by_tags
@@ -44,12 +45,16 @@
4445
set_image_annotation_status, upload_annotations_from_json_to_image
4546
)
4647
from .db.project import get_project_metadata, search_projects
47-
from .db.project_images import copy_image, move_image, upload_image_to_project
48+
from .db.project_images import (
49+
assign_images, copy_image, move_image, pin_image, upload_image_to_project
50+
)
4851
from .db.projects import (
4952
create_project, create_project_like_project, delete_project,
50-
get_project_image_count, get_project_settings, get_project_workflow,
51-
rename_project, set_project_settings, set_project_workflow, share_project,
52-
unshare_project, upload_annotations_from_folder_to_project,
53+
get_project_default_image_quality_in_editor, get_project_image_count,
54+
get_project_settings, get_project_workflow, rename_project,
55+
set_project_default_image_quality_in_editor, set_project_settings,
56+
set_project_workflow, share_project, unshare_project,
57+
upload_annotations_from_folder_to_project,
5358
upload_images_from_folder_to_project,
5459
upload_images_from_s3_bucket_to_project, upload_images_to_project,
5560
upload_preannotations_from_folder_to_project, upload_video_to_project,
@@ -63,7 +68,6 @@
6368
SAExistingProjectNameException, SANonExistingAnnotationClassNameException,
6469
SANonExistingProjectNameException
6570
)
66-
from .consensus_benchmark.consensus import consensus
6771
from .input_converters.conversion import (
6872
convert_platform, convert_project_type, export_annotation_format,
6973
import_annotation_format

superannotate/__main__.py

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ def main():
4343
command = sys.argv[1]
4444
further_args = sys.argv[2:]
4545

46-
if command == "image-upload":
46+
if command == "upload-images":
4747
image_upload(further_args)
48+
elif command == "upload-videos":
49+
video_upload(further_args)
4850
elif command == "init":
4951
ask_token(further_args)
5052
elif command == "export-project":
@@ -59,6 +61,70 @@ def _list_str(values):
5961
return values.split(',')
6062

6163

64+
def video_upload(args):
65+
parser = argparse.ArgumentParser()
66+
parser.add_argument(
67+
'--project', required=True, help='Project name to upload'
68+
)
69+
parser.add_argument(
70+
'--folder', required=True, help='Folder from which to upload'
71+
)
72+
parser.add_argument(
73+
'--recursive',
74+
default=False,
75+
action='store_true',
76+
help='Enables recursive subfolder upload.'
77+
)
78+
parser.add_argument(
79+
'--extensions',
80+
required=False,
81+
default=None,
82+
type=_list_str,
83+
help=
84+
'List of video extensions to include. Default is mp4,avi,mov,webm,flv,mpg,ogg'
85+
)
86+
parser.add_argument(
87+
'--set-annotation-status',
88+
required=False,
89+
default="NotStarted",
90+
help=
91+
'Set images\' annotation statuses after upload. Default is NotStarted'
92+
)
93+
parser.add_argument(
94+
'--target-fps',
95+
required=False,
96+
default=None,
97+
help=
98+
'How many frames per second need to extract from the videos (approximate). If not specified all frames will be uploaded'
99+
)
100+
parser.add_argument(
101+
'--start-time',
102+
required=False,
103+
default=0.0,
104+
help=
105+
'Time (in seconds) from which to start extracting frames. Default is 0.0'
106+
)
107+
parser.add_argument(
108+
'--end-time',
109+
required=False,
110+
default=None,
111+
help=
112+
'Time (in seconds) up to which to extract frames. If it is not specified, then up to end'
113+
)
114+
args = parser.parse_args(args)
115+
116+
sa.upload_videos_from_folder_to_project(
117+
project=args.project,
118+
folder_path=args.folder,
119+
extensions=args.extensions,
120+
annotation_status=args.set_annotation_status,
121+
recursive_subfolders=args.recursive,
122+
target_fps=args.target_fps,
123+
start_time=args.start_time,
124+
end_time=args.end_time
125+
)
126+
127+
62128
def image_upload(args):
63129
parser = argparse.ArgumentParser()
64130
parser.add_argument(
@@ -89,10 +155,10 @@ def image_upload(args):
89155
args = parser.parse_args(args)
90156

91157
sa.upload_images_from_folder_to_project(
92-
args.project,
93-
args.folder,
94-
args.extensions,
95-
args.set_annotation_status,
158+
project=args.project,
159+
folder_path=args.folder,
160+
extensions=args.extensions,
161+
annotation_status=args.set_annotation_status,
96162
recursive_subfolders=args.recursive
97163
)
98164

superannotate/db/images.py

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -903,50 +903,49 @@ def upload_annotations_from_json_to_image(
903903
path=f'/image/{image_id}/annotation/getAnnotationUploadToken',
904904
params=params
905905
)
906-
if response.ok:
907-
res = response.json()
908-
if project_type == 1: # vector
909-
res = res['objects']
910-
s3_session = boto3.Session(
911-
aws_access_key_id=res['accessKeyId'],
912-
aws_secret_access_key=res['secretAccessKey'],
913-
aws_session_token=res['sessionToken']
914-
)
915-
s3_resource = s3_session.resource('s3')
916-
bucket = s3_resource.Bucket(res["bucket"])
917-
bucket.put_object(
918-
Key=res['filePath'], Body=json.dumps(annotation_json)
919-
)
920-
else: # pixel
921-
if mask is None:
922-
raise SABaseException(0, "Pixel annotation should have mask.")
923-
if not isinstance(mask, io.BytesIO):
924-
with open(mask, "rb") as f:
925-
mask = io.BytesIO(f.read())
926-
res_j = res['pixel']
927-
s3_session = boto3.Session(
928-
aws_access_key_id=res_j['accessKeyId'],
929-
aws_secret_access_key=res_j['secretAccessKey'],
930-
aws_session_token=res_j['sessionToken']
931-
)
932-
s3_resource = s3_session.resource('s3')
933-
bucket = s3_resource.Bucket(res_j["bucket"])
934-
bucket.put_object(
935-
Key=res_j['filePath'], Body=json.dumps(annotation_json)
936-
)
937-
res_m = res['save']
938-
s3_session = boto3.Session(
939-
aws_access_key_id=res_m['accessKeyId'],
940-
aws_secret_access_key=res_m['secretAccessKey'],
941-
aws_session_token=res_m['sessionToken']
942-
)
943-
s3_resource = s3_session.resource('s3')
944-
bucket = s3_resource.Bucket(res_m["bucket"])
945-
bucket.put_object(Key=res_m['filePath'], Body=mask)
946-
else:
906+
if not response.ok:
947907
raise SABaseException(
948908
response.status_code, "Couldn't upload annotation. " + response.text
949909
)
910+
res = response.json()
911+
if project_type == 1: # vector
912+
res = res['objects']
913+
s3_session = boto3.Session(
914+
aws_access_key_id=res['accessKeyId'],
915+
aws_secret_access_key=res['secretAccessKey'],
916+
aws_session_token=res['sessionToken']
917+
)
918+
s3_resource = s3_session.resource('s3')
919+
bucket = s3_resource.Bucket(res["bucket"])
920+
bucket.put_object(
921+
Key=res['filePath'], Body=json.dumps(annotation_json)
922+
)
923+
else: # pixel
924+
if mask is None:
925+
raise SABaseException(0, "Pixel annotation should have mask.")
926+
if not isinstance(mask, io.BytesIO):
927+
with open(mask, "rb") as f:
928+
mask = io.BytesIO(f.read())
929+
res_j = res['pixel']
930+
s3_session = boto3.Session(
931+
aws_access_key_id=res_j['accessKeyId'],
932+
aws_secret_access_key=res_j['secretAccessKey'],
933+
aws_session_token=res_j['sessionToken']
934+
)
935+
s3_resource = s3_session.resource('s3')
936+
bucket = s3_resource.Bucket(res_j["bucket"])
937+
bucket.put_object(
938+
Key=res_j['filePath'], Body=json.dumps(annotation_json)
939+
)
940+
res_m = res['save']
941+
s3_session = boto3.Session(
942+
aws_access_key_id=res_m['accessKeyId'],
943+
aws_secret_access_key=res_m['secretAccessKey'],
944+
aws_session_token=res_m['sessionToken']
945+
)
946+
s3_resource = s3_session.resource('s3')
947+
bucket = s3_resource.Bucket(res_m["bucket"])
948+
bucket.put_object(Key=res_m['filePath'], Body=mask)
950949

951950

952951
def create_fuse_image(

0 commit comments

Comments
 (0)