diff --git a/docs/changelog.md b/docs/changelog.md index 7f8ac31..4d0ef44 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -16,7 +16,7 @@ All notable changes to this project will be documented below. #### annotate.napari_label_classes -* v0.1dev: viewer = **annotate.napari_label_classes**(*img, classes, show=True*) +* v0.1dev: viewer = **annotate.napari_label_classes**(*img, classes, size=10, shape='square', importdata=False, show=True*) #### annotate.napari_open diff --git a/docs/napari_label_classes.md b/docs/napari_label_classes.md index 6b112af..6fab410 100644 --- a/docs/napari_label_classes.md +++ b/docs/napari_label_classes.md @@ -1,26 +1,26 @@ ## Label Image with Napari -This function opens an image in Napari and then defines a set of classes to label. A random shape label is assigned to each class. +This function opens an image in Napari and then defines a set of Points layers with the user-defined labels called `classes`. A random `shape` of the annotation symbol is assigned to each of the `classes`. Image can be annotated as long as viewer is open. -**plantcv.annotate.napari_label_classes*(*img, classes, show=True*) +**plantcv.annotate.napari_label_classes*(*img, classes, size=10, shape='square', importdata=False, show=True*) **returns** napari viewer object - **Parameters:** - img - image data (compatible with gray, RGB, and hyperspectral data. If data is hyperspecral it should be the array e.g. hyperspectral.array_data) - - classes - list of classes to label. If no points are selected for a class, - data without labels will default to this class when napari_join_labels - is run. If all classes have points labeled, any clusters not labeled - will default to the last class in the list if napari_join_labels is - run. - - show - if show = True, viewer is launched. False setting is useful for test purposes. + - classes - list of classes to label. This option is not necessary if data is data is imported. + - size - integer pixel size of label (also adjustable from the interactive Napari viewer) + - shape - shape of the annotation symbol. Can be 'o', 'arrow', 'clobber', 'cross', 'diamond', 'disc', 'hbar', 'ring', 'square' (default), 'star', 'tailed_arrow', + 'triangle_down', 'triangle_up', 'vbar', or 'x' (also adjustable from the interactive Napari viewer) + - importdata - dictionary of data, data saved from napari_save_coor or data imported from napari_read_coor + - show - if `show=True`, viewer is launched. `False` setting is useful for test purposes. - **Context:** - - Adding class labels to images. Works best on an image that has objects segmented/classified with contours/clusters labeled with values (e.g. labeled mask, output of kmeans clustering). + - Adding one or more classes of points layer for annotation of the image. - **Example use:** - - Labeling output of kmeans clustering into classes. Labeling points. + - Ground truth counting, labeling classes of objects of interest. ```python @@ -31,9 +31,8 @@ import napari # Create an instance of the Points class img, path, name = pcv.readimage("./grayimg.png") -viewer = pcvan.napari_label_classes(img=img, classes=['background', 'wing','seed']) - -# Should open interactive napari viewer +# Opens interactive napari viewer +viewer = pcvan.napari_label_classes(img=img, classes=['background', 'wing','seed'], size=30) ``` diff --git a/plantcv/annotate/napari_label_classes.py b/plantcv/annotate/napari_label_classes.py index 81e37dd..42b65c7 100755 --- a/plantcv/annotate/napari_label_classes.py +++ b/plantcv/annotate/napari_label_classes.py @@ -3,9 +3,11 @@ import numpy as np import random from plantcv.annotate import napari_open +from plantcv.annotate import napari_classes -def napari_label_classes(img, classes, show=True): +def napari_label_classes(img, classes=False, size=10, shape='square', + importdata=False, show=True): """ open img in napari and label classes @@ -19,7 +21,12 @@ def napari_label_classes(img, classes, show=True): is run. If all classes have points labeled, any clusters not labeled will default to the last class in the list when napari_join_labels is run. - show = if show is True the viewer is launched. This option is useful for + size = size of marker in pixels + shape = either 'square' or 'circle' + importdata = dictionary of values in Napari format (y,x). + Output of napari_read_coor + show = if show is True the viewer is launched. This opetion is useful for + running tests without triggering the viewer. Returns: @@ -27,18 +34,70 @@ def napari_label_classes(img, classes, show=True): :param img: numpy.ndarray :param classes: list + :param size: int + :param shape: str + :param importdata: dict + :param show: str + :return viewer: napari viewer object """ showcall = show viewer = napari_open(img, show=showcall) - symbols = ['arrow', 'clobber', 'cross', 'diamond', 'disc', 'hbar', 'ring', - 'square', 'star', 'tailed_arrow', 'triangle_down', - 'triangle_up', 'vbar'] + color = ["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", + "beige", "bisque", "black", "blanchedalmond", "blue", + "blueviolet", "brown", "burlywood", "cadetblue", + "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", + "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", + "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", + "darkred", "darksalmon", "darkseagreen", "darkslateblue", + "darkslategray", "darkturquoise", "darkviolet", "deeppink", + "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", + "ghostwhite", "gold", "goldenrod", "gray", "green", + "greenyellow", "honeydew", "hotpink", "indianred", + "indigo", "ivory", "khaki", "lavender", "lavenderblush", + "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", + "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", + "lightslategray", "lightsteelblue", "lightyellow", "lime", + "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", + "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", + "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", + "moccasin", "navajowhite", "navy", "oldlace", "olive", + "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", + "palegreen", "paleturquoise", "palevioletred", "papayawhip", + "peachpuff", "peru", "pink", "plum", "powderblue", "purple", + "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", + "silver", "skyblue", "slateblue", "slategray", "snow", + "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", + "turquoise", "violet", "wheat", "white", "whitesmoke", + "yellow", "yellowgreen"] + + keys = napari_classes(viewer) + + if classes is not False: + for x in classes: + if x not in keys: + viewer.add_points(np.array([]), name=x, symbol=shape, + edge_color=random.choice(color), + face_color=random.choice(color), size=size) + keys = napari_classes(viewer) - for x in classes: - viewer.add_points(np.array([]), name=x, symbol=random.choice(symbols), - face_color='white', size=10) + if importdata is not False: + importkeys = list(importdata.keys()) + for key in importkeys: + if len(importdata[key]) != 0: + if key in keys: + viewer.layers[key].add(importdata[key]) + else: + viewer.add_points(importdata[key], name=key, symbol=shape, + edge_color=random.choice(color), + face_color=random.choice(color), + size=size) return viewer diff --git a/tests/test_napari_label_classes.py b/tests/test_napari_label_classes.py index a2ba4f9..4661b1b 100644 --- a/tests/test_napari_label_classes.py +++ b/tests/test_napari_label_classes.py @@ -7,10 +7,13 @@ def test_napari_label_classes_gray(test_data): """Test for PlantCV.Annotate""" # Read in test data img, _, _ = readimage(test_data.kmeans_seed_gray_img) - viewer = napari_label_classes(img, ['seed'], show=False) - coor = [(25, 25)] - viewer.add_points(np.array(coor), symbol="o", name='background', - face_color="red", size=1) + data = {'total': [(25, 25)], 'background': [(50, 50)]} + viewer = napari_label_classes(img, ['total'], size=5, importdata=data, + show=False) + coor = [(50, 25)] + viewer.add_points(np.array(coor), symbol="o", name='coor', + face_color="red", size=5) + + assert len(viewer.layers['total'].data) == 1 - assert len(viewer.layers['background'].data) == 1 viewer.close()