Skip to content

Commit

Permalink
Merge pull request #13 from danforthcenter/napari-join-labels
Browse files Browse the repository at this point in the history
Napari join labels
  • Loading branch information
nfahlgren authored May 6, 2024
2 parents 9fe576f + 73ce255 commit c2ed906
Show file tree
Hide file tree
Showing 28 changed files with 1,200 additions and 21 deletions.
4 changes: 4 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[run]
omit =
config.py
config-3.py
16 changes: 12 additions & 4 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
env:
OS: ${{ matrix.os }}
PYTHON: ${{ matrix.python-version }}

DISPLAY: ':99.0'
steps:
- uses: actions/checkout@main
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -30,19 +30,27 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends libyaml-dev libegl1-mesa libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-shape0 libxcb-cursor0 xserver-xephyr xvfb
python -m pip install --upgrade pip
pip install flake8 pytest pytest-cov ipython
pip install flake8 pytest pytest-cov pytest-qt pytest-xvfb ipython anyio
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test and generate coverage report
- uses: tlambert03/setup-qt-libs@v1
- name: Install plantcv-annotate
# Run coverage analysis on pytest tests
run: |
pip install .
py.test --cov-report=xml --cov=./
pip uninstall -y opencv-python
pip install opencv-python-headless
- name: Tests
uses: aganders3/headless-gui@v2
with:
run: pytest --cov-report=xml --cov=./
- name: Upload coverage to Deepsource
uses: deepsourcelabs/test-coverage-action@master
with:
Expand Down
2 changes: 1 addition & 1 deletion docs/Points.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Interactive Point Annotation Tool

Using [Jupyter Notebooks](jupyter.md) it is possible to interactively click to collect coordinates from an image, which can be used in various downstream applications. Left click on the image to collect a point. Right click removes the
Using [Jupyter Notebooks](https://plantcv.readthedocs.io/en/stable/jupyter/) it is possible to interactively click to collect coordinates from an image, which can be used in various downstream applications. Left click on the image to collect a point. Right click removes the
closest collected point.

**plantcv.annotate.Points**(*img, figsize=(12,6), label="dafault"*)
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.
32 changes: 32 additions & 0 deletions docs/napari_classes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Open Image with Napari

Get class names from Napari Viewer Object.

**plantcv.annotate.napari_classes**(*viewer*)

**returns** list of napari classes

- **Parameters:**
- viewer - Napari viewer object

- **Context:**
- Get names of Napari classes. This is mainly an internal function but can be useful in other context.

- **Example use:**
- Get names of Napari classes/labels.


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

# 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'])

classes = pcvan.napari_classes(viewer)

```

**Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annotate/napari_classes.py)
45 changes: 45 additions & 0 deletions docs/napari_join_labels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Join Labels with Napari

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*)

**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,
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.

- **Context:**
- This function would be run after labeling classes in Napari is complete.

- **Example use:**
- Joining classes labeled as the same, for example for joining classes from output of kmeans clustering


```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("./grayimg.png")

viewer = pcvan.napari_label_classes(img=img, ['background', 'wing','seed'])

# Should open interactive napari viewer

labeledmask, mask_dict = pcvan.napari_join_lables(img=img, viewer=viewer)

```

![Screenshot](img/documentation_images/napari_label_classes/napari_label_classes.png)

![Screenshot](img/documentation_images/napari_join_labels/1_labeled_mask.png)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annotate/napari_label_classes.py)
43 changes: 43 additions & 0 deletions docs/napari_label_classes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## 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.
Image can be annotated as long as viewer is open.

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

- **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).

- **Example use:**
- Labeling output of kmeans clustering into classes. Labeling points.


```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("./grayimg.png")

viewer = pcvan.napari_label_classes(img=img, classes=['background', 'wing','seed'])

# Should open interactive napari viewer

```

![Screenshot](img/documentation_images/napari_label_classes/napari_label_classes.png)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annotate/napari_label_classes.py)
36 changes: 36 additions & 0 deletions docs/napari_open.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Open Image with Napari

Open image data (e.g. RGB, gray, hyperspectral) with an interactive Napari viewer. If a gray image is opened, the image will be pseudocolored for better visualization.

**plantcv.annotate.napari_open**(*img, 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)
- show - if show = True, viewer is launched. False setting is useful for test purposes.

- **Context:**
- Used to open image data with Napari.

- **Example use:**
- Open image data to annotate it with other Napari functions (e.g. napari_label_classes)


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

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

viewer = pcvan.napari_open(img=img)

# Should open interactive napari viewer

```

![Screenshot](img/documentation_images/napari_open/napari_open.png)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv-annotate/blob/main/plantcv/annotate/napari_open.py)
33 changes: 33 additions & 0 deletions environment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# run: conda env create --file environment.yml
# optionally, change channel name with -n {plantcv-dev}
name: plantcv
dependencies:
- python=3.10
- matplotlib>=1.5
- numpy>=1.11
- pandas
- python-dateutil
- scipy
- scikit-image>=0.19
- scikit-learn
- dask
- dask-jobqueue
- opencv
- statsmodels
- xarray>=2022.11.0
- mkdocs
- pytest
- pytest-cov
- flake8
- ipympl
- nodejs
- jupyterlab
- altair
- vl-convert-python
- napari
- pyqt
- pytest-qt

channels:
- conda-forge
- defaults
4 changes: 4 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ nav:
- 'Adding/Editing Documentation': documentation.md
- 'PlantCV Namespace':
- 'Annotation Tools':
- Napari Classes: napari_classes.md
- Napari Join: napari_join_labels.md
- Napari Label: napari_label_classes.md
- Napari Open: napari_open.md
- Points: Points.md
- Get Centroids: get_centroids.md
markdown_extensions:
Expand Down
10 changes: 9 additions & 1 deletion plantcv/annotate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
from importlib.metadata import version
from plantcv.annotate.classes import Points
from plantcv.annotate.get_centroids import get_centroids
from plantcv.annotate.napari_classes import napari_classes
from plantcv.annotate.napari_open import napari_open
from plantcv.annotate.napari_label_classes import napari_label_classes
from plantcv.annotate.napari_join_labels import napari_join_labels

# Auto versioning
__version__ = version("plantcv-annotate")

__all__ = [
"Points",
"get_centroids"
"get_centroids",
"napari_classes",
"napari_open",
"napari_label_classes",
"napari_join_labels"
]
31 changes: 31 additions & 0 deletions plantcv/annotate/napari_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Get Napari Keys

import re


def napari_classes(viewer):
"""
get names of napari keys
Inputs:
viewer = napari viewer object
Returns:
classes = napari class value names
:param viewer: napari.viewer.Viewer
:return labels: numpy.ndarray, list
"""
keylist = list(viewer.layers)
keylist = ''.join(str(keylist))
keylist = keylist.split(',')

classes = []
for x in keylist:
if re.search('Image layer', x):
pass
else:
y = x.split(" ")
classes.append(y[3].strip("\'"))

return classes
Loading

0 comments on commit c2ed906

Please sign in to comment.