Skip to content

Commit 302dc81

Browse files
authored
Merge pull request #627 from superannotateai/friday
Friday
2 parents 79534f2 + 339d734 commit 302dc81

File tree

23 files changed

+177
-121
lines changed

23 files changed

+177
-121
lines changed

docs/source/api_reference/helpers.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,3 @@ ________________________
2222
.. _ref_aggregate_annotations_as_df:
2323
.. automethod:: superannotate.SAClient.validate_annotations
2424
.. automethod:: superannotate.SAClient.aggregate_annotations_as_df
25-
26-
----------
27-
28-
Utility functions
29-
--------------------------------
30-
31-
.. autofunction:: superannotate.SAClient.consensus

docs/source/userguide/quickstart.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ It can be installed on Ubuntu with:
2525
2626
sudo apt-get install ffmpeg
2727
28-
To use the :py:obj:`consensus` function on Windows and Mac platforms, you might also need to install the shapely package
29-
beforehand. The package works well only under the Anaconda distribution with:
30-
31-
.. code-block:: bash
32-
33-
conda install shapely
34-
3528
----------
3629

3730

docs/source/userguide/utilities.rst

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -126,64 +126,3 @@ Example of created DataFrame:
126126

127127
Each row represents annotation information. One full annotation with multiple
128128
attribute groups can be grouped under :code:`instanceId` field.
129-
130-
131-
Working with DICOM files
132-
------------------------
133-
134-
JPEG images with names :file:`<dicom_file_name>_<frame_num>.jpg` will be created
135-
in :file:`<path_to_output_dir>`. Those JPEG images can be uploaded to
136-
SuperAnnotate platform using the regular:
137-
138-
.. code-block:: python
139-
140-
sa.upload_images_from_folder_to_project(project, "<path_to_output_dir>")
141-
142-
Some DICOM files can have image frames that are compressed. To load them, `GDCM :
143-
Grassroots DICOM library <http://gdcm.sourceforge.net/wiki/index.php/Main_Page>`_ needs to be installed:
144-
145-
.. code-block:: bash
146-
147-
# using conda
148-
conda install -c conda-forge gdcm
149-
150-
# or on Ubuntu with versions above 19.04
151-
sudo apt install python3-gdcm
152-
153-
Computing consensus scores for instances between several projects
154-
-----------------------------------------------------------------
155-
156-
157-
Consensus is a tool to compare the quallity of the annotations of the same image that is present in several projects.
158-
To compute the consensus scores:
159-
160-
.. code-block:: python
161-
162-
res_df = sa.consensus([project_names], "<path_to_export_folder>", [image_list], "<annotation_type>")
163-
164-
Here pandas DataFrame with following columns is returned: creatorEmail, imageName, instanceId, className, area, attribute, projectName, score
165-
166-
.. image:: images/consensus_dataframe.png
167-
168-
Besides the pandas DataFrame there is an option to get the following plots by setting the show_plots flag to True:
169-
170-
* Box plot of consensus scores for each annotators
171-
* Box plot of consensus scores for each project
172-
* Scatter plots of consensus score vs instance area for each project
173-
174-
.. code-block:: python
175-
176-
sa.consensus([project_names], "<path_to_export_folder>", [image_list], "<annotation_type>", show_plots=True)
177-
178-
To the left of each box plot the original score points of that annotator is depicted, the box plots are colored by annotator.
179-
180-
.. image:: images/consensus_annotators_box.png
181-
182-
Analogically the box plots of consensus scores for each project are colored according to project name.
183-
184-
.. image:: images/consensus_projects_box.png
185-
186-
Scatter plot of consensus score vs instance area is separated by projects. Hovering on a point reveals its annotator and image name.
187-
The points are colored according to class name. Each annotator is represented with separate symbol.
188-
189-
.. image:: images/consensus_scatter.png

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pandas~=1.3
99
ffmpeg-python~=0.2
1010
pillow~=9.5
1111
aiofiles==23.1.0
12-
requests==2.30.0
12+
requests==2.31.0
1313
tqdm==4.64.0
1414
fire==0.4.0
1515
mixpanel==4.8.3

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ def get_folder_by_id(self, project_id: int, folder_id: int):
156156
response = self.controller.get_folder_by_id(
157157
folder_id=folder_id, project_id=project_id
158158
)
159-
160-
return FolderSerializer(response).serialize(
159+
response.raise_for_status()
160+
return FolderSerializer(response.data).serialize(
161161
exclude={"completedCount", "is_root"}
162162
)
163163

@@ -173,12 +173,13 @@ def get_item_by_id(self, project_id: int, item_id: int):
173173
:return: item metadata
174174
:rtype: dict
175175
"""
176-
176+
project_response = self.controller.get_project_by_id(project_id=project_id)
177+
project_response.raise_for_status()
177178
response = self.controller.get_item_by_id(
178-
item_id=item_id, project_id=project_id
179+
item_id=item_id, project=project_response.data
179180
)
180181

181-
return ItemSerializer(response).serialize(exclude={"url", "meta"})
182+
return ItemSerializer(response.data).serialize(exclude={"url", "meta"})
182183

183184
def get_team_metadata(self):
184185
"""Returns team metadata
@@ -1513,10 +1514,6 @@ def download_export(
15131514
to_s3_bucket=None,
15141515
):
15151516
"""Download prepared export.
1516-
1517-
WARNING: Starting from version 1.9.0 :ref:`download_export <ref_download_export>` additionally
1518-
requires :py:obj:`project` as first argument.
1519-
15201517
:param project: project name
15211518
:type project: str
15221519
:param export: export name

src/superannotate/lib/core/__init__.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,36 @@ def setup_logging(level=DEFAULT_LOGGING_LEVEL, file_path=LOG_FILE_LOCATION):
153153

154154
INVALID_JSON_MESSAGE = "Invalid json"
155155

156+
PROJECT_SETTINGS_VALID_ATTRIBUTES = [
157+
"Brightness",
158+
"Fill",
159+
"Contrast",
160+
"ShowLabels",
161+
"ShowComments",
162+
"Image",
163+
"Lines",
164+
"AnnotatorFinish",
165+
"PointSize",
166+
"FontSize",
167+
"WorkflowEnable",
168+
"ClassChange",
169+
"ShowEntropy",
170+
"UploadImages",
171+
"DeleteImages",
172+
"Download",
173+
"RunPredictions",
174+
"RunSegmentations",
175+
"ImageQuality",
176+
"ImageAutoAssignCount",
177+
"FrameMode",
178+
"FrameRate",
179+
"JumpBackward",
180+
"JumpForward",
181+
"UploadFileType",
182+
"Tokenization",
183+
"ImageAutoAssignEnable",
184+
]
185+
156186
__alL__ = (
157187
FolderStatus,
158188
ProjectStatus,

src/superannotate/lib/core/repositories.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ def __init__(
3636
secret_key: str,
3737
session_token: str,
3838
bucket: str,
39+
region: str,
3940
):
4041
self._session = boto3.Session(
4142
aws_access_key_id=access_key,
4243
aws_secret_access_key=secret_key,
4344
aws_session_token=session_token,
45+
region_name=region,
4446
)
4547

4648
self._resource = self._session.resource("s3")

src/superannotate/lib/core/usecases/annotations.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -591,13 +591,20 @@ def prepare_annotation(self, annotation: dict, size) -> dict:
591591
)
592592
return annotation
593593

594+
@staticmethod
595+
def get_mask_path(path: str) -> str:
596+
if path.endswith(constants.PIXEL_ANNOTATION_POSTFIX):
597+
replacement = constants.PIXEL_ANNOTATION_POSTFIX
598+
else:
599+
replacement = ".json"
600+
parts = path.rsplit(replacement, 1)
601+
return constants.ANNOTATION_MASK_POSTFIX.join(parts)
602+
594603
async def get_annotation(
595604
self, path: str
596605
) -> (Optional[Tuple[io.StringIO]], Optional[io.BytesIO]):
597606
mask = None
598-
mask_path = path.replace(
599-
constants.PIXEL_ANNOTATION_POSTFIX, constants.ANNOTATION_MASK_POSTFIX
600-
)
607+
mask_path = self.get_mask_path(path)
601608
if self._client_s3_bucket:
602609
content = self.get_annotation_from_s3(self._client_s3_bucket, path).read()
603610
if self._project.type == constants.ProjectType.PIXEL.value:

src/superannotate/lib/core/usecases/folders.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,12 @@ def execute(self):
2929
project_id=self._project_id,
3030
team_id=self._team_id,
3131
)
32+
if not response.ok:
33+
self._response.errors = AppException(response.error)
3234
except AppException as e:
3335
self._response.errors = e
3436
else:
3537
self._response.data = response.data
36-
37-
if not response.ok:
38-
self._response.errors = AppException(response.error)
39-
4038
return self._response
4139

4240

src/superannotate/lib/core/usecases/images.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,7 @@ def s3_repo(self):
756756
self._auth_data.data["secretAccessKey"],
757757
self._auth_data.data["sessionToken"],
758758
self._auth_data.data["bucket"],
759+
self._auth_data.data["region"],
759760
)
760761

761762
def validate_project_type(self):
@@ -952,6 +953,7 @@ def s3_repository(self):
952953
self.auth_data["secretAccessKey"],
953954
self.auth_data["sessionToken"],
954955
self.auth_data["bucket"],
956+
self.auth_data["region"],
955957
)
956958
return self._s3_repo_instance
957959

0 commit comments

Comments
 (0)