Skip to content

Commit

Permalink
Merge pull request #32 from danforthcenter/30-napari-draw-mask
Browse files Browse the repository at this point in the history
napari draw mask & remove "shape" param from napari_label_classes
  • Loading branch information
HaleySchuhl authored Sep 13, 2024
2 parents 888e3db + 12b1a34 commit e40c11b
Show file tree
Hide file tree
Showing 20 changed files with 171 additions and 31 deletions.
6 changes: 5 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ All notable changes to this project will be documented below.

#### annotate.napari_label_classes

* v0.1dev: viewer = **annotate.napari_label_classes**(*img, classes, size=10, shape='square', importdata=False, show=True*)
* v0.1dev: viewer = **annotate.napari_label_classes**(*img, classes, size=10, importdata=False, show=True*)

#### annotate.napari_open

* v0.1dev: viewer = **annotate.napari_open**(*img, mode = 'native', show=True*)

#### annotate.napari_points_mask

* v0.1dev: mask_dict = **annotate.napari_points_mask**(*img, viewer*)

#### annotate.napari_read_coor

* v0.1dev: data = **annotate.napari_read_coor**(*coor, dataformat='yx'*)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions docs/napari_join_labels.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

This function joins classes with the same label. This function would be run after classes are labeled with napari_label_classes.

**plantcv.annotate.napari_join_labels*(*img, viewer*)
**plantcv.annotate.napari_join_labels**(*img, viewer*)

**returns** relabeled mask, dictionary of masks for each class

- **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)
- viewer - viewer with labeled classes. If no points are selected for a class,
- viewer - viewer with labeled classes(likely created with [`napari_label_classes`](napari_label_classes.md)).
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.
run.

- **Context:**
- This function would be run after labeling classes in Napari is complete.
Expand Down
5 changes: 2 additions & 3 deletions docs/napari_label_classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
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, size=10, shape='square', importdata=False, show=True*)

**plantcv.annotate.napari_label_classes**(*img, classes, size=10, 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. 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.

Expand Down
60 changes: 60 additions & 0 deletions docs/napari_points_mask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Make Mask of Napari Points

This function is to generate a mask from Napari point information.
This application of this function could be to get information about image
at particular points (e.g. color or intensity information)

**plantcv.annotate.napari_points_mask**(*img, viewer*)

**returns** dictionary of masks (one for each class where the class label is the key to access)

- **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)
- viewer = Napari Viewer with point classes labeled (likely created with [`napari_label_classes`](napari_label_classes.md)). The size of the points in the mask will be determined from the viewer parameters.

- **Context:**
- This function can be used to generate a mask from Napari points in order to get information about point data.

- **Example use:**
- An application of this function might be collection of color data for the [Naive Bayes module](https://plantcv.readthedocs.io/en/latest/tutorials/machine_learning_tutorial/).


```python
import plantcv.plantcv as pcv
import plantcv.annotate as pcvan
import napari

# Create an instance of the Points class
img, path, name = pcv.readimage("./wheat.png")

# Should open interactive napari viewer
viewer = pcvan.napari_label_classes(img=img, classes=['background','healthy', 'rust', 'chlorosis'], size=4)

maskdict = pcvan.napari_points_mask(img, viewer)

pcv.plot_image(maskdict['background'])
pcv.plot_image(maskdict['healthy'])
pcv.plot_image(maskdict['rust'])
pcv.plot_image(maskdict['chlorosis'])

```

![Screenshot](img/documentation_images/napari_points_mask/viewer_labeled.png)

***Background Mask***

![Screenshot](img/documentation_images/napari_points_mask/background.png)

***Healthy Mask***

![Screenshot](img/documentation_images/napari_points_mask/healthy.png)

***Rust Mask***

![Screenshot](img/documentation_images/napari_points_mask/rust.png)

***Chlorosis Mask***

![Screenshot](img/documentation_images/napari_points_mask/chlorosis.png)

**Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annotate/napari_points_mask.py)
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ nav:
- Napari Join: napari_join_labels.md
- Napari Label: napari_label_classes.md
- Napari Open: napari_open.md
- Napari Points Mask: napari_points_mask.md
- Napari Read Coor: napari_read_coor.md
- Napari Save Coor: napari_save_coor.md
- Points: Points.md
Expand Down
4 changes: 3 additions & 1 deletion plantcv/annotate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from plantcv.annotate.napari_join_labels import napari_join_labels
from plantcv.annotate.napari_save_coor import napari_save_coor
from plantcv.annotate.napari_read_coor import napari_read_coor
from plantcv.annotate.napari_points_mask import napari_points_mask

# Auto versioning
__version__ = version("plantcv-annotate")
Expand All @@ -19,5 +20,6 @@
"napari_label_classes",
"napari_join_labels",
"napari_save_coor",
"napari_read_coor"
"napari_read_coor",
"napari_points_mask"
]
9 changes: 4 additions & 5 deletions plantcv/annotate/napari_label_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from plantcv.annotate import napari_classes


def napari_label_classes(img, classes=False, size=10, shape='square',
def napari_label_classes(img, classes=False, size=10,
importdata=False, show=True):
"""
open img in napari and label classes
Expand All @@ -22,7 +22,6 @@ def napari_label_classes(img, classes=False, size=10, shape='square',
will default to the last class in the list when napari_join_labels is
run.
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
Expand All @@ -35,7 +34,6 @@ def napari_label_classes(img, classes=False, size=10, shape='square',
:param img: numpy.ndarray
:param classes: list
:param size: int
:param shape: str
:param importdata: dict
:param show: str
Expand Down Expand Up @@ -83,7 +81,7 @@ def napari_label_classes(img, classes=False, size=10, shape='square',
if classes is not False:
for x in classes:
if x not in keys:
viewer.add_points(np.array([]), name=x, symbol=shape,
viewer.add_points(np.array([]), name=x, symbol='square',
edge_color=random.choice(color),
face_color=random.choice(color), size=size)
keys = napari_classes(viewer)
Expand All @@ -95,7 +93,8 @@ def napari_label_classes(img, classes=False, size=10, shape='square',
if key in keys:
viewer.layers[key].add(importdata[key])
else:
viewer.add_points(importdata[key], name=key, symbol=shape,
viewer.add_points(importdata[key], name=key,
symbol='square',
edge_color=random.choice(color),
face_color=random.choice(color),
size=size)
Expand Down
2 changes: 1 addition & 1 deletion plantcv/annotate/napari_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import cv2
import numpy as np
from skimage.color import label2rgb
import napari
from skimage.color import label2rgb


def napari_open(img, mode='native', show=True):
Expand Down
55 changes: 55 additions & 0 deletions plantcv/annotate/napari_points_mask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Make Masks of Labelled Napari Points

import numpy as np
import os
import cv2
from plantcv.annotate import napari_classes
from plantcv.plantcv import params
from plantcv.plantcv._debug import _debug


def napari_points_mask(img, viewer):
"""
draw points mask based on Napari viewer annotations
Inputs:
img = img (grayimg, rgbimg, or hyperspectral image array data
e.g. hyperspectraldata.array_data). This is used to find the x,y size
of the image
viewer = Napari Viewer with classes labeled. The size of the masked points
will be from the viewer parameters
Returns:
mask_dict = dictionary of masks; mask for each labelled class
:param img: numpy.ndarray
:param viewer: Napari Viewer object
:param shape: str
:return mask_dict: dict of numpy.ndarray
"""
# get shape of image
size = np.shape(img)
keys = napari_classes(viewer)
maskdict = {}

for key in keys:
maskname = str(key)
mask = np.zeros((size[0], size[1]))
data = list(viewer.layers[key].data)
shapesize = viewer.layers[key]._current_size
shapesizehalf = int(shapesize/2)

for y, x in data:
startpoint = (int(x-shapesizehalf), int(y-shapesizehalf))
endpoint = (int(x+shapesizehalf-1), int(y+shapesizehalf-1))
mask = cv2.rectangle(mask, startpoint, endpoint, (255), -1)

maskdict[maskname] = mask

_debug(visual=mask, filename=os.path.join(params.debug_outdir,
str(params.device) +
str(maskname) +
'_labeled_mask.png'))

return maskdict
4 changes: 2 additions & 2 deletions tests/test_napari_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ def test_napari_classes(make_napari_viewer):
img = np.zeros((100, 100))
coor = [(25, 25), (50, 50)]
viewer.add_image(img)
viewer.add_points(np.array(coor), symbol="o", name="total",
viewer.add_points(np.array(coor), symbol="square", name="total",
face_color="red", size=30)
viewer.add_points(np.array(coor), symbol="o", name="test",
viewer.add_points(np.array(coor), symbol="square", name="test",
face_color="red", size=30)
keys = napari_classes(viewer)

Expand Down
22 changes: 11 additions & 11 deletions tests/test_napari_join_labels.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import numpy as np
from plantcv.annotate.napari_open import napari_open
from plantcv.annotate.napari_label_classes import napari_label_classes
from plantcv.annotate import napari_open
from plantcv.annotate import napari_label_classes
from plantcv.plantcv import readimage
from plantcv.annotate.napari_join_labels import napari_join_labels
from plantcv.annotate import napari_join_labels
from plantcv.plantcv import params


Expand All @@ -23,10 +23,10 @@ def test_napari_join_allclass(test_data):
img, _, _ = readimage(test_data.kmeans_seed_gray_img)
viewer = napari_open(img, show=False)
background = [(54, 143), (77, 246)]
viewer.add_points(np.array(background), symbol="o", name='background',
viewer.add_points(np.array(background), symbol="square", name='background',
face_color="red", size=1)
wing = [(275, 54)]
viewer.add_points(np.array(wing), symbol="o", name='wing',
viewer.add_points(np.array(wing), symbol="square", name='wing',
face_color="red", size=1)
seed = [(280, 218)]
viewer.add_points(np.array(seed), symbol="o", name='seed',
Expand All @@ -44,13 +44,13 @@ def test_napari_join_warn(test_data):
img, _, _ = readimage(test_data.kmeans_seed_gray_img)
viewer = napari_open(img, show=False)
background = [(54, 143), (77, 246)]
viewer.add_points(np.array(background), symbol="o", name='background',
viewer.add_points(np.array(background), symbol="square", name='background',
face_color="red", size=1)
wing = [(275, 54)]
viewer.add_points(np.array(wing), symbol="o", name='wing',
viewer.add_points(np.array(wing), symbol="square", name='wing',
face_color="red", size=1)
seed = [(275, 54)]
viewer.add_points(np.array(seed), symbol="o", name='seed',
viewer.add_points(np.array(seed), symbol="square", name='seed',
face_color="red", size=1)

labeled, _ = napari_join_labels(img, viewer)
Expand All @@ -68,13 +68,13 @@ def test_napari_join_print(test_data, tmpdir):
img, _, _ = readimage(test_data.kmeans_seed_gray_img)
viewer = napari_open(img, show=False)
background = [(54, 143), (77, 246)]
viewer.add_points(np.array(background), symbol="o", name='background',
viewer.add_points(np.array(background), symbol="square", name='background',
face_color="red", size=1)
wing = [(280, 218)]
viewer.add_points(np.array(wing), symbol="o", name='wing',
viewer.add_points(np.array(wing), symbol="square", name='wing',
face_color="red", size=1)
seed = [(275, 54)]
viewer.add_points(np.array(seed), symbol="o", name='seed',
viewer.add_points(np.array(seed), symbol="square", name='seed',
face_color="red", size=1)

labeled, _ = napari_join_labels(img, viewer)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_napari_label_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_napari_label_classes_gray(test_data):
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',
viewer.add_points(np.array(coor), symbol="square", name='coor',
face_color="red", size=5)

assert len(viewer.layers['total'].data) == 1
Expand Down
4 changes: 2 additions & 2 deletions tests/test_napari_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_napari_open_gray(test_data):
img, _, _ = readimage(test_data.kmeans_seed_gray_img)
viewer = napari_open(img, show=False)
coor = [(25, 25), (50, 50)]
viewer.add_points(np.array(coor), symbol="o", name="total",
viewer.add_points(np.array(coor), symbol="square", name="total",
face_color="red", size=1)

assert len(viewer.layers['total'].data) == 2
Expand All @@ -49,7 +49,7 @@ def test_napari_open_envi(test_data):
img = img.array_data
viewer = napari_open(img, show=False)
coor = [(25, 25), (50, 50)]
viewer.add_points(np.array(coor), symbol="o", name="total",
viewer.add_points(np.array(coor), symbol="square", name="total",
face_color="red", size=1)

assert len(viewer.layers['total'].data) == 2
Expand Down
19 changes: 19 additions & 0 deletions tests/test_napari_points_mask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from plantcv.annotate import napari_points_mask
from plantcv.plantcv import readimage
from plantcv.annotate import napari_label_classes
import numpy as np


def test_napari_points_mask(test_data):
"""Test for PlantCV.Annotate"""
# Read in test data
img, _, _ = readimage(test_data.small_rgb_img)
data = {'total': [(25, 25)], 'background': [(50, 50)]}
viewer = napari_label_classes(img, ['total'], size=50, importdata=data,
show=False)
maskdict = napari_points_mask(img, viewer)

summask = int((np.sum(maskdict['total']))/255)

assert summask == 2500
viewer.close()
2 changes: 1 addition & 1 deletion tests/test_napari_save_coor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def test_napari_save_coor(test_data, tmpdir):
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',
viewer.add_points(np.array(coor), symbol="square", name='background',
face_color="red", size=1)

filename = os.path.join(cache_dir, 'tempfile.txt')
Expand Down

0 comments on commit e40c11b

Please sign in to comment.