diff --git a/docs/Points.md b/docs/Points.md index 0d1d169..5233315 100644 --- a/docs/Points.md +++ b/docs/Points.md @@ -25,10 +25,9 @@ closest collected point. - **Context:** - Used to define a list of coordinates of interest. - - - **Example use:** - - (pcv.roi.multi) - - (pcv.roi.custom) + - pcv.roi.multi + - pcv.roi.custom ```python @@ -44,6 +43,131 @@ marker = an.Points(img=img, figsize=(12,6)) roi = pcv.roi.custom(img=img, vertices=marker.coords['default']) ``` +**plantcv.annotate.Points.view**(*label="default", color="r", view_all=False*) +- **Parameters:** + - label - The current label (default = "default") + - color - The current color for annotations (default = "r") + - view_all - View all classes or a single class, by (default =`False`) + +**plantcv.annotate.Points.save_coords**() + +- **Context:** + - Once point annotations are collected, save the list of coordinates with their class label to Outputs and later saved out to file + +**plantcv.annotate.Points.save_counts**() + +- **Context:** + - Once point annotations are collected, save the dictionary of counts with their class label to Outputs and later saved out to file + +- **Example use:** + - Remove noise from a microscopy image that is otherwise difficult to filter out with traditional computer vision + techniques, and recover stomata that were filtered out during mask cleaning. + +**Original Image with Annotations: "total" pollen** + +![Screenshot](img/documentation_images/points_save/all_pollen.png) + +**Original Image with Annotations: "germinated" pollen** + +![Screenshot](img/documentation_images/points_save/germinated_pollen.png) + +```python +import plantcv.plantcv as pcv +import plantcv.annotate as pcvan + +# Create an instance of the Points class +img, path, name = pcv.readimage("stomata.tif") + +# Segmentation & mask clean up steps here + +# Create an instance of the Points class & click on stomata +marker = pcvan.Points(img=img, figsize=(12,6)) + +marker.save_coords() +marker.save_counts() + +pcv.outputs.observations + +{'total': {'coordinates': {'trait': 'collected coordinates', + 'method': 'annotation', + 'scale': 'none', + 'datatype': "", + 'value': [(113, 58), + (353, 105), + (74, 240), + (103, 297), + (278, 333), + (185, 350), + (237, 335), + (244, 285), + (300, 192), + (295, 151), + (262, 178), + (321, 44), + (187, 158), + (160, 187), + (65, 186)], + 'label': 'none'}, + 'object_count': {'trait': 'count of category', + 'method': 'count', + 'scale': 'count', + 'datatype': "", + 'value': 15, + 'label': 'none'}}, + 'germinated': {'coordinates': {'trait': 'collected coordinates', + 'method': 'annotation', + 'scale': 'none', + 'datatype': "", + 'value': [(64, 186), (244, 286)], + 'label': 'none'}, + 'object_count': {'trait': 'count of category', + 'method': 'count', + 'scale': 'count', + 'datatype': "", + 'value': 2, + 'label': 'none'}}} +``` + +**plantcv.annotate.Points.print_coords**(*filename*) + +- **Context:** + - Once point annotations are collected, save the list of coordinates out to a text file called `filename`. + Can be utilized by non-PlantCV analysis or read back in with `.import_file` annotation method. + +**plantcv.annotate.Points.import_list**(*coords, label="default"*) + +- **Context:** + - Import a list of coordinates into an instance of the `Points` class. + +- **Example use:** + - Below + +```python +import plantcv.plantcv as pcv +import plantcv.annotate as pcvan + +centers = pcvan.get_centroids() +counter = pcvan.Points(img=img, figsize=(12,6)) +counter.import_list(coords=centers, label="detected") + +``` + +**plantcv.annotate.Points.import_file**(*filename*) + +- **Context:** + - Import a list of coordinates into an instance of the `Points` class. + +- **Example use:** + - Below + +```python +import plantcv.plantcv as pcv +import plantcv.annotate as pcvan + +drawer = pcvan.Points(img=img, figsize=(12,6)) +drawer.import_file(filename="replicate101_saved_coords.txt") ) + +``` **Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annoate/classes.py) diff --git a/docs/img/documentation_images/points_save/all_pollen.png b/docs/img/documentation_images/points_save/all_pollen.png new file mode 100644 index 0000000..f970273 Binary files /dev/null and b/docs/img/documentation_images/points_save/all_pollen.png differ diff --git a/docs/img/documentation_images/points_save/germinated_pollen.png b/docs/img/documentation_images/points_save/germinated_pollen.png new file mode 100644 index 0000000..95c8fd5 Binary files /dev/null and b/docs/img/documentation_images/points_save/germinated_pollen.png differ diff --git a/mkdocs.yml b/mkdocs.yml index eff0192..92bf827 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,6 +22,7 @@ nav: - Napari Label: napari_label_classes.md - Napari Open: napari_open.md - Points: Points.md + - Points Save: points_save.md - Get Centroids: get_centroids.md markdown_extensions: - toc: diff --git a/plantcv/annotate/classes.py b/plantcv/annotate/classes.py index 455701e..7dfdc34 100644 --- a/plantcv/annotate/classes.py +++ b/plantcv/annotate/classes.py @@ -5,8 +5,8 @@ import json from math import floor import matplotlib.pyplot as plt +from plantcv.plantcv import warn, outputs from plantcv.plantcv.annotate.points import _find_closest_pt -from plantcv.plantcv import warn class Points: @@ -79,6 +79,24 @@ def print_coords(self, filename): # Save the data in JSON format with indentation json.dump(obj=self.coords, fp=fp, indent=4) + def save_counts(self): + """Save collected coordinates to Outputs.observations""" + for key in self.count: + value = self.count[key] + outputs.add_observation(sample=key, variable="object_count", + trait='count of category', + method='count', scale='count', datatype=int, + value=value, label='none') + + def save_coords(self): + """Save collected coordinates to Outputs.observations""" + for key in self.count: + value = self.coords[key] + outputs.add_observation(sample=key, variable="coordinates", + trait='collected coordinates', + method='annotation', scale='none', datatype=list, + value=value, label='none') + def import_list(self, coords, label="default"): """Import coordinates. diff --git a/tests/test_annotate_points.py b/tests/test_annotate_points.py index d7828b3..aeae0e2 100644 --- a/tests/test_annotate_points.py +++ b/tests/test_annotate_points.py @@ -3,6 +3,7 @@ import cv2 import matplotlib from plantcv.annotate.classes import Points +from plantcv.plantcv import outputs def test_points(test_data): @@ -157,3 +158,22 @@ def test_points_view_warn(test_data): drawer_rgb.view(label="new", color='r') assert str(drawer_rgb.fig) == "Figure(500x500)" + +def test_points_save_coords(test_data): + img = cv2.imread(test_data.small_rgb_img) + drawer = Points(img=img) + # Populate attribute with coords + totalpoints1 = [(158, 531), (361, 112), (500, 418)] + drawer.coords = {'default': totalpoints1} + drawer.save_coords() + + assert outputs.observations["default"]["coordinates"]["value"] == [(158, 531), (361, 112), (500, 418)] + +def test_points_save_counts(test_data): + img = cv2.imread(test_data.small_rgb_img) + drawer = Points(img=img) + # Populate attribute with coords + drawer.count = {'default': 1} + drawer.save_counts() + + assert outputs.observations["default"]["object_count"]["value"] == 1