pathology-image-features 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pathology_image_features/__init__.py +0 -0
- pathology_image_features/ann_io/README.md +51 -0
- pathology_image_features/ann_io/__init__.py +33 -0
- pathology_image_features/ann_io/convert.py +340 -0
- pathology_image_features/ann_io/read.py +123 -0
- pathology_image_features/ann_io/write.py +108 -0
- pathology_image_features/ontology/__init__.py +372 -0
- pathology_image_features/ontology/classes/Resource/Container/Container.py +39 -0
- pathology_image_features/ontology/classes/Resource/Container/SpatialObjectCollection/SpatialObjectCollection.py +307 -0
- pathology_image_features/ontology/classes/Resource/Container/SpatialObjectCollection/__init__.py +11 -0
- pathology_image_features/ontology/classes/Resource/Container/__init__.py +3 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/__init__.py +3 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/directed_graph/__init__.py +7 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/directed_graph/directed_graph.py +42 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/directed_graph/nearest_neighbor_graph/__init__.py +3 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/directed_graph/nearest_neighbor_graph/nearest_neighbor_graph.py +59 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/network_graph.py +22 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/undirected_graph/__init__.py +3 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/undirected_graph/undirected_acyclic_graph/__init__.py +3 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/undirected_graph/undirected_acyclic_graph/undirected_acyclic_graph.py +60 -0
- pathology_image_features/ontology/classes/Resource/Container/network_graph/undirected_graph/undirected_graph.py +32 -0
- pathology_image_features/ontology/classes/Resource/Container/tessellation/__init__.py +3 -0
- pathology_image_features/ontology/classes/Resource/Container/tessellation/tessellation.py +244 -0
- pathology_image_features/ontology/classes/Resource/Resource.py +23 -0
- pathology_image_features/ontology/classes/Resource/__init__.py +3 -0
- pathology_image_features/ontology/classes/SpatialObject/SpatialObject.py +252 -0
- pathology_image_features/ontology/classes/SpatialObject/__init__.py +7 -0
- pathology_image_features/ontology/classes/__init__.py +308 -0
- pathology_image_features/ontology/classes/information_content_entity/__init__.py +5 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/__init__.py +3 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_entity.py +19 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/__init__.py +9 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/data_transformation_parameter.py +36 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/numeric_parameter/__init__.py +7 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/numeric_parameter/numeric_parameter.py +42 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/spatial_predicate/__init__.py +23 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/spatial_predicate/spatial_predicate.py +182 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/string_parameter/__init__.py +7 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/data_transformation_parameter/string_parameter/string_parameter.py +89 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/__init__.py +5 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/data_set_of_features/__init__.py +3 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/data_set_of_features/data_set_of_features.py +130 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/homogenous_data_collection.py +31 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/image_data_set/__init__.py +7 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/image_data_set/annotated_image_data_set/__init__.py +11 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/image_data_set/annotated_image_data_set/annotated_image_data_set.py +211 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/homogenous_data_collection/image_data_set/image_data_set.py +358 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/image_data_set_annotation/__init__.py +11 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/image_data_set_annotation/image_data_set_annotation.py +192 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/image_data_set_annotation/image_data_set_pixel_mask/__init__.py +9 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/image_data_set_annotation/image_data_set_pixel_mask/image_data_set_heat_map/__init__.py +0 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/image_data_set_annotation/image_data_set_pixel_mask/image_data_set_heat_map/image_data_set_heat_map.py +32 -0
- pathology_image_features/ontology/classes/information_content_entity/data_entity/image_data_set_annotation/image_data_set_pixel_mask/image_data_set_pixel_mask.py +262 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/__init__.py +3 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/directive_information_entity.py +22 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/__init__.py +7 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/algorithm/__init__.py +3 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/algorithm/algorithm.py +22 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/algorithm/machine_learning_algorithm/__init__.py +6 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/algorithm/machine_learning_algorithm/machine_learning_algorithm.py +27 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/plan_specification.py +44 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/software/__init__.py +17 -0
- pathology_image_features/ontology/classes/information_content_entity/directive_information_entity/plan_specification/software/software.py +80 -0
- pathology_image_features/ontology/classes/information_content_entity/information_content_entity.py +33 -0
- pathology_image_features/ontology/classes/information_content_entity/value_specification/__init__.py +3 -0
- pathology_image_features/ontology/classes/information_content_entity/value_specification/scalar_value_specification/__init__.py +3 -0
- pathology_image_features/ontology/classes/information_content_entity/value_specification/scalar_value_specification/scalar_value_specification.py +35 -0
- pathology_image_features/ontology/classes/information_content_entity/value_specification/value_specification.py +22 -0
- pathology_image_features/ontology/classes/process/__init__.py +5 -0
- pathology_image_features/ontology/classes/process/planned_process/__init__.py +6 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/__init__.py +7 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/completely_executed_planned_process.py +19 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_annotation/__init__.py +7 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_annotation/data_annotation.py +60 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/__init__.py +5 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_aggregation_process/__init__.py +6 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_aggregation_process/data_aggregation_process.py +47 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_aggregation_process/descriptive_statistical_calculation_data_transformation/__init__.py +31 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_aggregation_process/descriptive_statistical_calculation_data_transformation/descriptive_statistical_calculation_data_transformation.py +248 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_filtration_process/__init__.py +0 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_filtration_process/data_filtration_process.py +61 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/data_transformation.py +285 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/__init__.py +7 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_based_machine_learning_algorithm_execution/__init__.py +5 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_based_machine_learning_algorithm_execution/image_based_machine_learning_algorithm_execution.py +34 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_based_machine_learning_algorithm_execution/image_based_machine_learning_algorithm_inference/__init__.py +11 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_based_machine_learning_algorithm_execution/image_based_machine_learning_algorithm_inference/image_based_machine_learning_algorithm_inference.py +85 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/__init__.py +7 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_characteristic_quantification_process.py +76 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_intensity_characteristic_quantification_process/__init__.py +13 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_intensity_characteristic_quantification_process/image_intensity_characteristic_quantification_process.py +95 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_morphological_characteristic_quantification_process/__init__.py +7 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_morphological_characteristic_quantification_process/image_morphological_characteristic_quantification_process.py +33 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_morphological_characteristic_quantification_process/image_shape_characteristic_quantification_process/__init__.py +21 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_morphological_characteristic_quantification_process/image_shape_characteristic_quantification_process/image_shape_characteristic_quantification_process.py +567 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_morphological_characteristic_quantification_process/image_size_characteristic_quantification_process/__init__.py +17 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_morphological_characteristic_quantification_process/image_size_characteristic_quantification_process/image_size_characteristic_quantification_process.py +283 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_spatial_position_characteristic_quantification_process/__init__.py +15 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_spatial_position_characteristic_quantification_process/image_spatial_position_characteristic_quantification_process.py +224 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_spatial_position_characteristic_quantification_process/image_spatial_relationship_characteristic_quantification_process/__init__.py +23 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_characteristic_quantification_process/image_spatial_position_characteristic_quantification_process/image_spatial_relationship_characteristic_quantification_process/image_spatial_relationship_characteristic_quantification_process.py +206 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_data_set_analysis.py +35 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_data_set_annotation_transformation/__init__.py +13 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/image_data_set_analysis/image_data_set_annotation_transformation/image_data_set_annotation_transformation.py +303 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/network_analysis/__init__.py +13 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/network_analysis/network_analysis.py +52 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/network_analysis/network_graph_construction/__init__.py +6 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/network_analysis/network_graph_construction/nearest_neighbor_graph_construction/__init__.py +9 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/network_analysis/network_graph_construction/nearest_neighbor_graph_construction/nearest_neighbor_graph_construction.py +156 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/network_analysis/network_graph_construction/network_graph_construction.py +71 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/tessellation_analysis/__init__.py +5 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/tessellation_analysis/tessellation_analysis.py +60 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/tessellation_analysis/tessellation_construction/__init__.py +11 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/data_transformation/tessellation_analysis/tessellation_construction/tessellation_construction.py +121 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/machine_learning/__init__.py +13 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/machine_learning/machine_learning.py +101 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/machine_learning/machine_learning_model_inference/__init__.py +11 -0
- pathology_image_features/ontology/classes/process/planned_process/completely_executed_planned_process/machine_learning/machine_learning_model_inference/machine_learning_model_inference.py +83 -0
- pathology_image_features/ontology/classes/process/planned_process/planned_process.py +19 -0
- pathology_image_features/ontology/classes/process/process.py +19 -0
- pathology_image_features/ontology/classes/unit/__init__.py +5 -0
- pathology_image_features/ontology/classes/unit/angle_unit/__init__.py +5 -0
- pathology_image_features/ontology/classes/unit/angle_unit/angle_unit.py +21 -0
- pathology_image_features/ontology/classes/unit/angle_unit/plane_angle_unit/__init__.py +7 -0
- pathology_image_features/ontology/classes/unit/angle_unit/plane_angle_unit/plane_angle_unit.py +47 -0
- pathology_image_features/ontology/classes/unit/area_unit/__init__.py +15 -0
- pathology_image_features/ontology/classes/unit/area_unit/area_unit.py +52 -0
- pathology_image_features/ontology/classes/unit/dimensionless_unit/__init__.py +6 -0
- pathology_image_features/ontology/classes/unit/dimensionless_unit/dimensionless_unit.py +30 -0
- pathology_image_features/ontology/classes/unit/dimensionless_unit/ratio_unit/__init__.py +8 -0
- pathology_image_features/ontology/classes/unit/dimensionless_unit/ratio_unit/ratio_unit.py +32 -0
- pathology_image_features/ontology/classes/unit/information_unit/__init__.py +7 -0
- pathology_image_features/ontology/classes/unit/information_unit/image_resolution_unit/__init__.py +4 -0
- pathology_image_features/ontology/classes/unit/information_unit/image_resolution_unit/image_resolution_unit.py +19 -0
- pathology_image_features/ontology/classes/unit/information_unit/image_resolution_unit/spatial_resolution_unit/__init__.py +5 -0
- pathology_image_features/ontology/classes/unit/information_unit/image_resolution_unit/spatial_resolution_unit/spatial_resolution_unit.py +27 -0
- pathology_image_features/ontology/classes/unit/information_unit/information_unit.py +35 -0
- pathology_image_features/ontology/classes/unit/length_unit/__init__.py +7 -0
- pathology_image_features/ontology/classes/unit/length_unit/length_unit.py +36 -0
- pathology_image_features/ontology/classes/unit/unit.py +19 -0
- pathology_image_features/ontology/datatypes.py +20 -0
- pathology_image_features/ontology/individuals/__init__.py +0 -0
- pathology_image_features/ontology/individuals/unit.py +86 -0
- pathology_image_features/ontology/pifo.owl +5615 -0
- pathology_image_features/ontology/properties/__init__.py +304 -0
- pathology_image_features/ontology/restrictions/__init__.py +582 -0
- pathology_image_features/utils/README.md +9 -0
- pathology_image_features/utils/__init__.py +0 -0
- pathology_image_features/utils/general.py +268 -0
- pathology_image_features/utils/visualization.py +251 -0
- pathology_image_features-0.2.0.dist-info/METADATA +65 -0
- pathology_image_features-0.2.0.dist-info/RECORD +154 -0
- pathology_image_features-0.2.0.dist-info/WHEEL +4 -0
- pathology_image_features-0.2.0.dist-info/licenses/LICENSE +21 -0
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# *pathology-image-features* I/O module
|
|
2
|
+
|
|
3
|
+
This module contains methods for input and output of various annotation types.
|
|
4
|
+
|
|
5
|
+
Supported datatypes include:
|
|
6
|
+
|
|
7
|
+
- *large-image*
|
|
8
|
+
- Extensions: .json
|
|
9
|
+
- Schema: https://girder.github.io/large_image/annotations.html
|
|
10
|
+
- Functions:
|
|
11
|
+
- Read: `read_histomics`
|
|
12
|
+
- Convert: `histomics_to_geojson`, `histomics_to_aperio`
|
|
13
|
+
- Write: `write_histomics`
|
|
14
|
+
|
|
15
|
+
- *GeoJSON*
|
|
16
|
+
- Extensions: .json, .geojson
|
|
17
|
+
- Schema: https://geojson.org/
|
|
18
|
+
- Functions:
|
|
19
|
+
- Read: `read_geojson`
|
|
20
|
+
- Convert: `geojson_to_histomics`, `geojson_to_aperio`
|
|
21
|
+
- Write: `write_geojson`
|
|
22
|
+
|
|
23
|
+
- *Aperio ImageScope*
|
|
24
|
+
- Extensions: .xml
|
|
25
|
+
- Schema: (None provided)
|
|
26
|
+
- Functions:
|
|
27
|
+
- Read: `read_aperio`
|
|
28
|
+
- Convert: `aperio_to_geojson`, `aperio_to_histomics`
|
|
29
|
+
- Write: `write_aperio`
|
|
30
|
+
|
|
31
|
+
- *Parquet*
|
|
32
|
+
- Extensions: .csv
|
|
33
|
+
- Schema: (see GeoJSON)
|
|
34
|
+
- Functions:
|
|
35
|
+
- Read: (In Progress)
|
|
36
|
+
- Convert: (In Progress)
|
|
37
|
+
- Write: (In Progress)
|
|
38
|
+
|
|
39
|
+
- *Image annotation types*: (see below)
|
|
40
|
+
- Extensions: .jpg, .png, .tiff, .ome.tiff, ...
|
|
41
|
+
- Schema: (see below)
|
|
42
|
+
- Functions:
|
|
43
|
+
- Read: (In Progress)
|
|
44
|
+
- Convert: (In Progress)
|
|
45
|
+
- Write: (In Progress)
|
|
46
|
+
|
|
47
|
+
Image annotation types
|
|
48
|
+
- "label-mask"
|
|
49
|
+
- 2D mask with a single "class" where each unique index above zero corresponds to one "object"
|
|
50
|
+
- "one-hot"
|
|
51
|
+
- ND mask where each channel is a "class" and each unique index above zero corresponds to one "object" for that "class"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from .convert import (
|
|
2
|
+
aperio_to_geojson,
|
|
3
|
+
aperio_to_histomics,
|
|
4
|
+
geojson_to_aperio,
|
|
5
|
+
geojson_to_histomics,
|
|
6
|
+
histomics_to_aperio,
|
|
7
|
+
histomics_to_geojson,
|
|
8
|
+
)
|
|
9
|
+
from .read import (
|
|
10
|
+
read_aperio,
|
|
11
|
+
read_geojson,
|
|
12
|
+
read_histomics,
|
|
13
|
+
)
|
|
14
|
+
from .write import (
|
|
15
|
+
write_aperio,
|
|
16
|
+
write_geojson,
|
|
17
|
+
write_histomics,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"aperio_to_geojson",
|
|
22
|
+
"aperio_to_histomics",
|
|
23
|
+
"geojson_to_aperio",
|
|
24
|
+
"geojson_to_histomics",
|
|
25
|
+
"histomics_to_aperio",
|
|
26
|
+
"histomics_to_geojson",
|
|
27
|
+
"read_aperio",
|
|
28
|
+
"read_geojson",
|
|
29
|
+
"read_histomics",
|
|
30
|
+
"write_aperio",
|
|
31
|
+
"write_geojson",
|
|
32
|
+
"write_histomics",
|
|
33
|
+
]
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Functions for converting from one annotation format to another
|
|
4
|
+
|
|
5
|
+
Steps:
|
|
6
|
+
- Convert to GeoJSON (if not already GeoJSON)
|
|
7
|
+
- Convert GeoJSON to desired format
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
import pandas as pd
|
|
15
|
+
from lxml import etree as ET
|
|
16
|
+
from typing_extensions import Union
|
|
17
|
+
|
|
18
|
+
from ..utils.general import unique_id
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def histomics_to_geojson(anns: Union[list[dict], dict]) -> Union[list[dict], dict]:
|
|
22
|
+
"""Converting Histomics/large-image formatted annotations to GeoJSON
|
|
23
|
+
|
|
24
|
+
:param anns: One or more Histomics/large-image formatted annotations
|
|
25
|
+
:type anns: Union[list,dict]
|
|
26
|
+
:return: Same annotations but in GeoJSON format
|
|
27
|
+
:rtype: Union[list,dict]
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
if type(anns) is dict:
|
|
31
|
+
anns = [anns]
|
|
32
|
+
|
|
33
|
+
geojson_anns = []
|
|
34
|
+
for ann in anns:
|
|
35
|
+
ann_id = ann.get("_id", unique_id())
|
|
36
|
+
|
|
37
|
+
geojson_ann = {
|
|
38
|
+
"type": "FeatureCollection",
|
|
39
|
+
"properties": {"name": ann["annotation"].get("name", ""), "_id": ann_id},
|
|
40
|
+
"features": [],
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for el_idx, el in enumerate(ann["annotation"].get("elements", [])):
|
|
44
|
+
if el.get("type") == "polyline":
|
|
45
|
+
coords = [el["points"]]
|
|
46
|
+
elif el.get("type") == "rectangle":
|
|
47
|
+
coords = [
|
|
48
|
+
[
|
|
49
|
+
[
|
|
50
|
+
el["center"][0] - (el["width"] / 2),
|
|
51
|
+
el["center"][1] - (el["height"] / 2),
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
el["center"][0] + (el["width"] / 2),
|
|
55
|
+
el["center"][1] - (el["height"] / 2),
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
el["center"][0] + (el["width"] / 2),
|
|
59
|
+
el["center"][1] + (el["height"] / 2),
|
|
60
|
+
],
|
|
61
|
+
[
|
|
62
|
+
el["center"][0] - (el["width"] / 2),
|
|
63
|
+
el["center"][1] + (el["height"] / 2),
|
|
64
|
+
],
|
|
65
|
+
[
|
|
66
|
+
el["center"][0] - (el["width"] / 2),
|
|
67
|
+
el["center"][1] + (el["height"] / 2),
|
|
68
|
+
],
|
|
69
|
+
]
|
|
70
|
+
]
|
|
71
|
+
else:
|
|
72
|
+
print(f"element type: {el.get('type')} is not implemented")
|
|
73
|
+
|
|
74
|
+
# Checking if there are holes
|
|
75
|
+
holes_list = el.get("holes", [])
|
|
76
|
+
|
|
77
|
+
props_dict = {
|
|
78
|
+
"name": ann["annotation"].get("name", ""),
|
|
79
|
+
"_id": unique_id(),
|
|
80
|
+
"_index": el_idx,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if "user" in el:
|
|
84
|
+
props_dict = el["user"] | props_dict
|
|
85
|
+
|
|
86
|
+
geojson_ann["features"].append(
|
|
87
|
+
{
|
|
88
|
+
"type": "Feature",
|
|
89
|
+
"geometry": {
|
|
90
|
+
"type": "Polygon",
|
|
91
|
+
"coordinates": coords
|
|
92
|
+
if len(holes_list) == 0
|
|
93
|
+
else coords + holes_list,
|
|
94
|
+
},
|
|
95
|
+
"properties": props_dict,
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
geojson_anns.append(geojson_ann)
|
|
100
|
+
|
|
101
|
+
if len(anns) == 1:
|
|
102
|
+
geojson_anns = geojson_anns[0]
|
|
103
|
+
|
|
104
|
+
return geojson_anns
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def aperio_to_geojson(xml_tree) -> Union[list, dict]:
|
|
108
|
+
"""Converting Aperio ImageScope formatted annotations to GeoJSON
|
|
109
|
+
|
|
110
|
+
:param xml_tree: An XML E-Tree that is the output of read_aperio
|
|
111
|
+
:type xml_tree: None
|
|
112
|
+
:return: A list of GeoJSON FeatureCollections for each Annotation
|
|
113
|
+
:rtype: Union[list,dict]
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
layers_in_xml = xml_tree.findall("Annotation")
|
|
117
|
+
geojson_anns = []
|
|
118
|
+
for ann_idx in range(0, len(layers_in_xml)):
|
|
119
|
+
layer_name = (
|
|
120
|
+
f"Layer {ann_idx + 1}",
|
|
121
|
+
) # TODO: Get the XML layer's "Label" property here
|
|
122
|
+
|
|
123
|
+
geojson_ann = {
|
|
124
|
+
"type": "FeatureCollection",
|
|
125
|
+
"features": [],
|
|
126
|
+
"properties": {"name": layer_name, "_id": unique_id()},
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
layer_regions = xml_tree.findall(
|
|
130
|
+
f'Annotation[@Id="{ann_idx + 1}"]/Regions/Region'
|
|
131
|
+
)
|
|
132
|
+
# Iterating through Regions
|
|
133
|
+
for r_idx, r in enumerate(layer_regions):
|
|
134
|
+
vertices = r.findall("./Vertices/Vertex")
|
|
135
|
+
coords = []
|
|
136
|
+
for vert in vertices:
|
|
137
|
+
coords.append(
|
|
138
|
+
[int(float(vert.attrib["X"])), int(float(vert.attrib["Y"]))]
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
geojson_ann["features"].append(
|
|
142
|
+
{
|
|
143
|
+
"type": "Feature",
|
|
144
|
+
"geometry": {"type": "Polygon", "coordinates": [coords]},
|
|
145
|
+
"properties": {
|
|
146
|
+
"name": layer_name,
|
|
147
|
+
"_id": unique_id(),
|
|
148
|
+
"_index": r_idx,
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
geojson_anns.append(geojson_ann)
|
|
154
|
+
|
|
155
|
+
if len(geojson_anns) == 1:
|
|
156
|
+
geojson_anns = geojson_anns[0]
|
|
157
|
+
|
|
158
|
+
return geojson_anns
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def geojson_to_histomics(anns: Union[list, dict]) -> Union[list, dict]:
|
|
162
|
+
"""Converting GeoJSON formatted annotations to Histomics/large-image
|
|
163
|
+
|
|
164
|
+
:param anns: One or more GeoJSON formatted annotations
|
|
165
|
+
:type anns: Union[list,dict]
|
|
166
|
+
:return: List or single Histomics formatted annotation
|
|
167
|
+
:rtype: Union[list,dict]
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
if type(anns) is dict:
|
|
171
|
+
anns = [anns]
|
|
172
|
+
|
|
173
|
+
histomics_anns = []
|
|
174
|
+
for g in anns:
|
|
175
|
+
g_name = g.get("properties", {}).get("name", "")
|
|
176
|
+
|
|
177
|
+
histomics_ann = {
|
|
178
|
+
"annotation": {
|
|
179
|
+
"name": g_name,
|
|
180
|
+
"elements": [
|
|
181
|
+
{
|
|
182
|
+
"type": "polyline",
|
|
183
|
+
"user": f.get("properties", {}),
|
|
184
|
+
"closed": True,
|
|
185
|
+
"points": [
|
|
186
|
+
list(i) + [0] if type(i) is tuple else i + [0]
|
|
187
|
+
for i in f["geometry"]["coordinates"][0]
|
|
188
|
+
],
|
|
189
|
+
"holes": [
|
|
190
|
+
list(i) + [0] if type(i) is tuple else i + [0]
|
|
191
|
+
for i in f["geometry"]["coordinates"][1]
|
|
192
|
+
]
|
|
193
|
+
if len(f["geometry"]["coordinates"]) == 2
|
|
194
|
+
else [],
|
|
195
|
+
}
|
|
196
|
+
if all([len(i) == 2 for i in f["geometry"]["coordinates"][0]])
|
|
197
|
+
else {
|
|
198
|
+
"type": "polyline",
|
|
199
|
+
"user": f.get("properties", {}),
|
|
200
|
+
"closed": True,
|
|
201
|
+
"points": [
|
|
202
|
+
list(i) if type(i) is tuple else i
|
|
203
|
+
for i in f["geometry"]["coordinates"][0]
|
|
204
|
+
],
|
|
205
|
+
"holes": [
|
|
206
|
+
list(i) if type(i) is tuple else i
|
|
207
|
+
for i in f["geometry"]["coordinates"][1]
|
|
208
|
+
]
|
|
209
|
+
if len(f["geometry"]["coordinates"]) == 2
|
|
210
|
+
else [],
|
|
211
|
+
}
|
|
212
|
+
for f in g["features"]
|
|
213
|
+
],
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
histomics_anns.append(histomics_ann)
|
|
217
|
+
|
|
218
|
+
if len(histomics_anns) == 1:
|
|
219
|
+
histomics_anns = histomics_anns[0]
|
|
220
|
+
|
|
221
|
+
return histomics_anns
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def geojson_to_aperio(anns: Union[list, dict]) -> ET._ElementTree:
|
|
225
|
+
"""Converting GeoJSON formatted annotations to Aperio ImageScope format
|
|
226
|
+
|
|
227
|
+
:param anns: One or more GeoJSON annotations
|
|
228
|
+
:type anns: Union[list,dict]
|
|
229
|
+
"""
|
|
230
|
+
output_xml = ET.Element("Annotations")
|
|
231
|
+
|
|
232
|
+
if type(anns) is dict:
|
|
233
|
+
anns = [anns]
|
|
234
|
+
|
|
235
|
+
for a_idx, a in enumerate(anns):
|
|
236
|
+
a_layer = ET.SubElement(
|
|
237
|
+
output_xml,
|
|
238
|
+
"Annotation",
|
|
239
|
+
attrib={
|
|
240
|
+
"Type": "4",
|
|
241
|
+
"Visible": "1",
|
|
242
|
+
"ReadOnly": "0",
|
|
243
|
+
"Incremental": "0",
|
|
244
|
+
"LineColorReadOnly": "0",
|
|
245
|
+
"Id": "1",
|
|
246
|
+
"NameReadOnly": "0",
|
|
247
|
+
"LayerName": a.get("properties", {}).get("name", f"Layer {a_idx + 1}"),
|
|
248
|
+
},
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
a_regions = ET.SubElement(a_layer, "Regions")
|
|
252
|
+
|
|
253
|
+
for g_idx, g in enumerate(a.get("features", [])):
|
|
254
|
+
region = ET.SubElement(
|
|
255
|
+
a_regions,
|
|
256
|
+
"Region",
|
|
257
|
+
attrib={
|
|
258
|
+
"NegativeROA": "0",
|
|
259
|
+
"ImageFocus": "-1",
|
|
260
|
+
"DisplayId": str(g_idx + 1),
|
|
261
|
+
"InputRegionId": "0",
|
|
262
|
+
"Analyze": "0",
|
|
263
|
+
"Type": "0",
|
|
264
|
+
"Id": str(g_idx + 1),
|
|
265
|
+
},
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
vertices = ET.SubElement(region, "Vertices")
|
|
269
|
+
|
|
270
|
+
for vert in g["geometry"]["coordinates"]:
|
|
271
|
+
if len(vert) == 2:
|
|
272
|
+
ET.SubElement(
|
|
273
|
+
vertices,
|
|
274
|
+
"Vertex",
|
|
275
|
+
attrib={"X": str(vert[0]), "Y": str(vert[1]), "Z": "0"},
|
|
276
|
+
)
|
|
277
|
+
elif len(vert) == 3:
|
|
278
|
+
ET.SubElement(
|
|
279
|
+
vertices,
|
|
280
|
+
"Vertex",
|
|
281
|
+
attrib={
|
|
282
|
+
"X": str(vert[0]),
|
|
283
|
+
"Y": str(vert[1]),
|
|
284
|
+
"Z": str(vert[2]),
|
|
285
|
+
},
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if len(g["geometry"]["coordinates"][0]) == 2:
|
|
289
|
+
ET.SubElement(
|
|
290
|
+
vertices,
|
|
291
|
+
"Vertex",
|
|
292
|
+
attrib={
|
|
293
|
+
"X": str(g["geometry"]["coordinates"][0][0]),
|
|
294
|
+
"Y": str(g["geometry"]["coordinates"][0][1]),
|
|
295
|
+
"Z": "0",
|
|
296
|
+
},
|
|
297
|
+
)
|
|
298
|
+
elif len(g["geometry"]["coordinates"][0]) == 3:
|
|
299
|
+
ET.SubElement(
|
|
300
|
+
vertices,
|
|
301
|
+
"Vertex",
|
|
302
|
+
attrib={
|
|
303
|
+
"X": str(g["geometry"]["coordinates"][0][0]),
|
|
304
|
+
"Y": str(g["geometry"]["coordinates"][0][1]),
|
|
305
|
+
"Z": str(g["geometry"]["coordinates"][0][2]),
|
|
306
|
+
},
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
output_xml_tree = output_xml.getroottree()
|
|
310
|
+
|
|
311
|
+
return output_xml_tree
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# These are the "lazy" implementations of converters
|
|
315
|
+
def aperio_to_histomics(xml_tree: ET._ElementTree) -> Union[list, dict]:
|
|
316
|
+
"""Converting Aperio ImageScope formatted annotations to Histomics
|
|
317
|
+
|
|
318
|
+
:param xml_tree: XML ETree object containing annotations
|
|
319
|
+
:type xml_tree: _type_
|
|
320
|
+
:return: One or more Histomics formatted annotation layers
|
|
321
|
+
:rtype: Union[list,dict]
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
geojson_anns = aperio_to_geojson(xml_tree)
|
|
325
|
+
histomics_anns = geojson_to_histomics(geojson_anns)
|
|
326
|
+
|
|
327
|
+
return histomics_anns
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def histomics_to_aperio(anns: Union[list, dict]) -> ET._ElementTree:
|
|
331
|
+
"""Converting Histomics/large-image formatted annotations to Aperio ImageScope
|
|
332
|
+
|
|
333
|
+
:param anns: One or more annotations in Histomics/large-image format
|
|
334
|
+
:type anns: Union[list,dict]
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
geojson_anns = histomics_to_geojson(anns)
|
|
338
|
+
aperio_anns = geojson_to_aperio(geojson_anns)
|
|
339
|
+
|
|
340
|
+
return aperio_anns
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Functions for reading different annotation types
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import functools
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
from lxml import etree as ET
|
|
13
|
+
from numpy.random.mtrand import f
|
|
14
|
+
from typing_extensions import Union
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def check_path(func):
|
|
18
|
+
"""Decorator function for checking if input file paths in a function exist
|
|
19
|
+
|
|
20
|
+
:param func: Function which takes a filepath as input
|
|
21
|
+
:type func: None
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@functools.wraps(func)
|
|
25
|
+
def reader(path):
|
|
26
|
+
assert os.path.exists(path), f"File: {path} not found!"
|
|
27
|
+
|
|
28
|
+
return func(path)
|
|
29
|
+
|
|
30
|
+
return reader
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def check_ext(allowed_exts: Union[list, None] = None):
|
|
34
|
+
"""Decorator function for checking if input file has correct extensions for a given reader.
|
|
35
|
+
|
|
36
|
+
:param allowed_exts: List of allowed file extensions, defaults to None
|
|
37
|
+
:type allowed_exts: Union[list,None], optional
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def wrapper(func):
|
|
41
|
+
@functools.wraps(func)
|
|
42
|
+
def reader(path):
|
|
43
|
+
if allowed_exts is not None:
|
|
44
|
+
assert path.split(".")[-1] in allowed_exts, (
|
|
45
|
+
f"File: {path} has incorrect extension ({path.split('.')[-1]}). Allowed extensions for this reader are: {allowed_exts}"
|
|
46
|
+
)
|
|
47
|
+
else:
|
|
48
|
+
pass
|
|
49
|
+
return func(path)
|
|
50
|
+
|
|
51
|
+
return reader
|
|
52
|
+
|
|
53
|
+
return wrapper
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@check_ext(["json"])
|
|
57
|
+
@check_path
|
|
58
|
+
def read_histomics(ann_path: str) -> Union[list, dict]:
|
|
59
|
+
"""Read annotations in Histomics/large-image format
|
|
60
|
+
|
|
61
|
+
For more details on this schema, see: https://girder.github.io/large_image/annotations.html
|
|
62
|
+
|
|
63
|
+
:param ann_path: Path to annotations file (.json extension)
|
|
64
|
+
:type ann_path: str
|
|
65
|
+
:return: Read annotations in original format
|
|
66
|
+
:rtype: Union[list,dict]
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
with open(ann_path, "r") as f:
|
|
70
|
+
read_anns = json.load(f)
|
|
71
|
+
f.close()
|
|
72
|
+
|
|
73
|
+
return read_anns
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@check_ext(["json", "geojson"])
|
|
77
|
+
@check_path
|
|
78
|
+
def read_geojson(ann_path: str) -> Union[list, dict]:
|
|
79
|
+
"""Read annotations in GeoJSON format
|
|
80
|
+
|
|
81
|
+
For more details on this schema, see: https://geojson.org/
|
|
82
|
+
|
|
83
|
+
:param ann_path: Path to annotation file
|
|
84
|
+
:type ann_path: str
|
|
85
|
+
:return: Read annotations in original format
|
|
86
|
+
:rtype: Union[list,dict]
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
with open(ann_path, "r") as f:
|
|
90
|
+
read_anns = json.load(f)
|
|
91
|
+
f.close()
|
|
92
|
+
|
|
93
|
+
return read_anns
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@check_ext(["xml"])
|
|
97
|
+
@check_path
|
|
98
|
+
def read_aperio(ann_path: str) -> ET._ElementTree:
|
|
99
|
+
"""Read annotations in Aperio ImageScope format
|
|
100
|
+
|
|
101
|
+
:param ann_path: Path to annotation file
|
|
102
|
+
:type ann_path: str
|
|
103
|
+
:return: Read annotations in original format
|
|
104
|
+
:rtype: Union[list,dict]
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
read_anns = ET.parse(ann_path)
|
|
108
|
+
|
|
109
|
+
return read_anns
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# TODO: Same as with read_aperio, "Original format" for Parquet annotations could be different from list/dict
|
|
113
|
+
@check_path
|
|
114
|
+
@check_ext(["csv", "parquet"])
|
|
115
|
+
def read_parquet(ann_path: str) -> Union[list, dict]:
|
|
116
|
+
"""Read annotations in Parquet format
|
|
117
|
+
|
|
118
|
+
:param ann_path: Path to annotation file
|
|
119
|
+
:type ann_path: str
|
|
120
|
+
:return: Read annotations in original format
|
|
121
|
+
:rtype: Union[list,dict]
|
|
122
|
+
"""
|
|
123
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Functions for writing different annotation types
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import functools
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
from lxml import etree as ET
|
|
13
|
+
from typing_extensions import Union
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def check_path(func):
|
|
17
|
+
"""Decorator function for checking if output path exists.
|
|
18
|
+
|
|
19
|
+
:param func: Function which takes a filepath as input argument for writing a file to
|
|
20
|
+
:type func: None
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
@functools.wraps(func)
|
|
24
|
+
def writer(anns, path):
|
|
25
|
+
assert os.path.isdir(f"{os.sep}".join(path.split(os.sep)[:-1])), (
|
|
26
|
+
f"Folder: {f'{os.sep}'.join(path.split(os.sep)[:-1])} not found!"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
return func(anns, path)
|
|
30
|
+
|
|
31
|
+
return writer
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def check_ext(allowed_exts: Union[list, None] = None):
|
|
35
|
+
"""Decorator function for checking if output file path has correct file extension
|
|
36
|
+
|
|
37
|
+
:param allowed_exts: List of allowed file extensions, defaults to None
|
|
38
|
+
:type allowed_exts: Union[list,None], optional
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def wrapper(func):
|
|
42
|
+
@functools.wraps(func)
|
|
43
|
+
def writer(anns, path):
|
|
44
|
+
if allowed_exts is not None:
|
|
45
|
+
assert path.split(".")[-1] in allowed_exts, (
|
|
46
|
+
f"Output file: {path.split(os.sep)[-1]} has incorrect extension ({path.split('.')[-1]}), Allowed extensions for this writer are: {allowed_exts}"
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
return func(anns, path)
|
|
52
|
+
|
|
53
|
+
return writer
|
|
54
|
+
|
|
55
|
+
return wrapper
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@check_ext(["json"])
|
|
59
|
+
@check_path
|
|
60
|
+
def write_histomics(anns: Union[list, dict], output_path: str):
|
|
61
|
+
"""Write annotations to Histomics/large-image format
|
|
62
|
+
|
|
63
|
+
For more details on this schema, see: https://girder.github.io/large_image/annotations.html
|
|
64
|
+
|
|
65
|
+
:param anns: One or more Histomics-formatted annotations
|
|
66
|
+
:type anns: Union[list,dict]
|
|
67
|
+
:param output_path: File path to save annotations to
|
|
68
|
+
:type output_path: str
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
with open(output_path, "w") as f:
|
|
72
|
+
json.dump(anns, f)
|
|
73
|
+
f.close()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@check_ext(["json", "geojson"])
|
|
77
|
+
@check_path
|
|
78
|
+
def write_geojson(anns: Union[list, dict], output_path: str):
|
|
79
|
+
"""Write annotations to GeoJSON format
|
|
80
|
+
|
|
81
|
+
for more details on this schema, see: https://geojson.org
|
|
82
|
+
|
|
83
|
+
:param anns: One or more GeoJSON-formatted annotations
|
|
84
|
+
:type anns: Union[list,dict]
|
|
85
|
+
:param output_path: File path to save annotations to
|
|
86
|
+
:type output_path: str
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
with open(output_path, "w") as f:
|
|
90
|
+
json.dump(anns, f)
|
|
91
|
+
f.close()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@check_ext(["xml"])
|
|
95
|
+
@check_path
|
|
96
|
+
def write_aperio(anns: ET._ElementTree, output_path: str):
|
|
97
|
+
"""Write annotations to Aperio ImageScope format
|
|
98
|
+
|
|
99
|
+
:param anns: Annotations in Aperio (XML) format
|
|
100
|
+
:type anns: ET._ElementTree
|
|
101
|
+
:param output_path: File path to save annotations to
|
|
102
|
+
:type output_path: str
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
xml_string = ET.tostring(anns, encoding="unicode", pretty_print=True)
|
|
106
|
+
with open(output_path, "w") as f:
|
|
107
|
+
f.write(xml_string)
|
|
108
|
+
f.close()
|