Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

30 napari draw mask #32

Merged
merged 22 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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