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

[WIP] Add slice interpolation #32

Open
wants to merge 28 commits into
base: main
Choose a base branch
from

Conversation

jamesyan-git
Copy link
Contributor

Allows users to draw labels on separate slices and interpolate in-between them
Still need to improve UI, add tests, etc...
Currently only works for first dimension

@jni
Copy link
Owner

jni commented May 30, 2022

This is looking very good @jamesyan-git! 😍 Looking forward to the ready-for-review!

from scipy.ndimage import distance_transform_edt


def distance_transform(image):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imho this should be renamed signed_distance_transform

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jamesyan-git can you rename this function? 😉

@codecov-commenter
Copy link

codecov-commenter commented Jun 27, 2022

Codecov Report

Merging #32 (345dddc) into main (0734529) will increase coverage by 6.37%.
The diff coverage is 100.00%.

📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more

@@            Coverage Diff             @@
##             main      #32      +/-   ##
==========================================
+ Coverage   78.11%   84.48%   +6.37%     
==========================================
  Files          15       17       +2     
  Lines         635      896     +261     
==========================================
+ Hits          496      757     +261     
  Misses        139      139              
Impacted Files Coverage Δ
src/zarpaint/_tests/test_watershed.py 100.00% <ø> (ø)
src/zarpaint/__init__.py 83.33% <100.00%> (+1.51%) ⬆️
src/zarpaint/_interpolate_labels.py 100.00% <100.00%> (ø)
src/zarpaint/_tests/test_interpolate_labels.py 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@GenevieveBuckley
Copy link
Contributor

Does the user interaction here require one to push the plugin start button before painting the first slice?

I generally have use cases where partial labels might generated with some other plugin or separate software, and want to correct any areas of innacuracy. For this use case, it's a plus if you can select an already drawn label for the first and/or last slice (or touch up a tiny region at an edge, then use the whole label area for slice interpolation).

I don't quite know how much you plan to rely on a temp intermediate memory state for the painting, so I want to mention the above workflow so we can prioritize it too.

@jamesyan-git
Copy link
Contributor Author

Hi @GenevieveBuckley ,
I totally understand about the use case regarding editing existing labels. I will aim to get this implemented once we are happy with the "from scratch" workflow. Below is a video showing the current workflow, where the following steps are taken:

  1. Create a labels layer, and select it from the dropdown
  2. Click "start Interpolation"
  3. Paint on desired slices with desired label ID(s)
  4. Once all the annotations have been made, click "interpolate"

@jni
https://user-images.githubusercontent.com/95660545/184786184-11f53309-2771-4eb6-9e9b-f5329cfacc41.mp4

Next steps:

  • add instruction blurb for users
  • add indicator of what mode you are in (more than the changing button text)
  • paintera like: update as soon as painting a new slice without clicking a button
  • keyboard shortcuts for start and end interpolate

I think this will put the annotate-from-scratch workflow in a good position and we can then start working on updating existing labels.
What are your thoughts?
I will keep adding docstrings and tests in the meantime.

@GenevieveBuckley
Copy link
Contributor

I think that sounds like a reasonable plan

@jamesyan-git jamesyan-git marked this pull request as ready for review September 28, 2022 03:03
@jamesyan-git
Copy link
Contributor Author

@DragaDoncila this is ready for review

@@ -42,3 +45,5 @@ contributions:
display_name: Split With Watershed
- command: zarpaint.copy_data
display_name: Copy Data
- command: zarpaint.interpolate_widg
display_name: Interpolate Slices
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
display_name: Interpolate Slices
display_name: Interpolate Slices with Signed Distance Transform

Just preparing for when we add future methods. I also hate that it's so hard for me to find out in other interpolation tools what method they're actually using!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like when we have future methods, there should be a dropdown selection box in the interpolation widget to switch between them (instead of creating additional widgets, which this comment seems to suggest).

@@ -23,6 +23,9 @@ contributions:
- id: zarpaint.copy_data
title: Copy Data…
python_name: zarpaint:copy_data
- id: zarpaint.interpolate_widg
title: Interpolate
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
title: Interpolate
title: Interpolate Slices with Signed Distance Transform

?

Maybe we can remove "signed" or Interpolate Slices (w/ Distance Transform) if length is an issue

@jni
Copy link
Owner

jni commented Oct 5, 2022

I just had a very quick look @jamesyan-git but it's looking good! I reckon add a couple of tests (interpolating 2D slices in 3D volume, and 3D in a 4D volume) and we merge!

@GenevieveBuckley
Copy link
Contributor

It looks like there's been a change in the way napari handles events since this PR was first added.

When I try this out today with napari 0.4.16, clicking the slice interpolation button gives this error:

AttributeError: 'EmitterGroup' object has no attribute 'paint'

related to line 202 in the enter_interpolation function:

self.selected_layer.events.paint.connect(self.paint_callback)
Error message:
Traceback (most recent call last):
  File "/Users/genevieb/mambaforge/envs/napari-empanada/lib/python3.9/site-packages/magicgui/widgets/_bases/value_widget.py", line 57, in _on_value_change
    self.changed.emit(value)
  File "psygnal/_signal.py", line 725, in psygnal._signal.SignalInstance.emit
  File "psygnal/_signal.py", line 767, in psygnal._signal.SignalInstance._run_emit_loop
  File "psygnal/_signal.py", line 768, in psygnal._signal.SignalInstance._run_emit_loop
  File "psygnal/_signal.py", line 788, in psygnal._signal.SignalInstance._run_emit_loop
  File "/Users/genevieb/Documents/GitHub/zarpaint/src/zarpaint/_interpolate_labels.py", line 252, in enter_interpolation
    self.selected_layer.events.paint.connect(self.paint_callback)
  File "/Users/genevieb/mambaforge/envs/napari-empanada/lib/python3.9/site-packages/napari/utils/_proxies.py", line 72, in __getattr__
    return self.create(super().__getattr__(name))
  File "/Users/genevieb/mambaforge/envs/napari-empanada/lib/python3.9/site-packages/napari/utils/events/event.py", line 971, in __getattr__
    return object.__getattribute__(self, name)
AttributeError: 'EmitterGroup' object has no attribute 'paint'
napari.sys_info():
napari: 0.4.16
Platform: macOS-12.3.1-arm64-arm-64bit
System: MacOS 12.3.1
Python: 3.10.6 | packaged by conda-forge | (main, Aug 22 2022, 20:41:22) [Clang 13.0.1 ]
Qt: 5.15.6
PyQt5: 5.15.7
NumPy: 1.23.4
SciPy: 1.9.3
Dask: 2022.10.2
VisPy: 0.10.0

OpenGL:
  - GL version:  2.1 Metal - 76.3
  - MAX_TEXTURE_SIZE: 16384

Screens:
  - screen 1: resolution 1440x900, scale 2.0
  - screen 2: resolution 1920x1080, scale 1.0

Plugins:
  - console: 0.0.6
  - napari-svg: 0.1.6
  - scikit-image: 0.4.16
  - zarpaint: 0.1.1.dev27+gfc48307
conda list:
# packages in environment at /Users/genevieb/mambaforge/envs/test-zarpaint:
#
# Name                    Version                   Build  Channel
alabaster                 0.7.12                     py_0    conda-forge
aom                       3.5.0                h7ea286d_0    conda-forge
appdirs                   1.4.4              pyh9f0ad1d_0    conda-forge
appnope                   0.1.3              pyhd8ed1ab_0    conda-forge
argon2-cffi               21.3.0             pyhd8ed1ab_0    conda-forge
argon2-cffi-bindings      21.2.0          py310h8e9501a_3    conda-forge
asciitree                 0.3.3                      py_2    conda-forge
asttokens                 2.1.0              pyhd8ed1ab_0    conda-forge
attrs                     22.1.0             pyh71513ae_1    conda-forge
babel                     2.10.3             pyhd8ed1ab_0    conda-forge
backcall                  0.2.0              pyh9f0ad1d_0    conda-forge
backports                 1.0                        py_2    conda-forge
backports.functools_lru_cache 1.6.4              pyhd8ed1ab_0    conda-forge
beautifulsoup4            4.11.1             pyha770c72_0    conda-forge
bleach                    5.0.1              pyhd8ed1ab_0    conda-forge
blosc                     1.21.1               hd414afc_3    conda-forge
bokeh                     2.4.3              pyhd8ed1ab_3    conda-forge
brotli                    1.0.9                h1a8c8d9_8    conda-forge
brotli-bin                1.0.9                h1a8c8d9_8    conda-forge
brotlipy                  0.7.0           py310h8e9501a_1005    conda-forge
brunsli                   0.1                  h9f76cd9_0    conda-forge
bzip2                     1.0.8                h3422bc3_4    conda-forge
c-ares                    1.18.1               h3422bc3_0    conda-forge
c-blosc2                  2.4.3                h303ed30_0    conda-forge
ca-certificates           2022.9.24            h4653dfc_0    conda-forge
cachey                    0.2.1              pyh9f0ad1d_0    conda-forge
certifi                   2022.9.24          pyhd8ed1ab_0    conda-forge
cffi                      1.15.1          py310h2399d43_2    conda-forge
cfitsio                   4.1.0                hd4f5c17_0    conda-forge
charls                    2.3.4                hbdafb3b_0    conda-forge
charset-normalizer        2.1.1              pyhd8ed1ab_0    conda-forge
click                     8.1.3           unix_pyhd8ed1ab_2    conda-forge
cloudpickle               2.2.0              pyhd8ed1ab_0    conda-forge
colorama                  0.4.6              pyhd8ed1ab_0    conda-forge
commonmark                0.9.1                      py_0    conda-forge
cryptography              38.0.2          py310h4fe9c50_2    conda-forge
cytoolz                   0.12.0          py310h8e9501a_1    conda-forge
dask                      2022.10.2          pyhd8ed1ab_0    conda-forge
dask-core                 2022.10.2          pyhd8ed1ab_0    conda-forge
dataclasses               0.8                pyhc8e2a94_3    conda-forge
dav1d                     1.0.0                he4db4b2_1    conda-forge
debugpy                   1.6.3           py310h0f1eb42_1    conda-forge
decorator                 5.1.1              pyhd8ed1ab_0    conda-forge
defusedxml                0.7.1              pyhd8ed1ab_0    conda-forge
distributed               2022.10.2          pyhd8ed1ab_0    conda-forge
docstring_parser          0.13               pyhd8ed1ab_0    conda-forge
docutils                  0.19            py310hbe9552e_1    conda-forge
entrypoints               0.4                pyhd8ed1ab_0    conda-forge
executing                 1.2.0              pyhd8ed1ab_0    conda-forge
expat                     2.5.0                hb7217d7_0    conda-forge
fasteners                 0.17.3             pyhd8ed1ab_0    conda-forge
flit-core                 3.7.1              pyhd8ed1ab_0    conda-forge
font-ttf-dejavu-sans-mono 2.37                 hab24e00_0    conda-forge
font-ttf-inconsolata      3.000                h77eed37_0    conda-forge
font-ttf-source-code-pro  2.038                h77eed37_0    conda-forge
font-ttf-ubuntu           0.83                 hab24e00_0    conda-forge
fontconfig                2.14.1               h82840c6_0    conda-forge
fonts-conda-ecosystem     1                             0    conda-forge
fonts-conda-forge         1                             0    conda-forge
freetype                  2.12.1               hd633e50_0    conda-forge
freetype-py               2.3.0              pyhd8ed1ab_0    conda-forge
fsspec                    2022.10.0          pyhd8ed1ab_0    conda-forge
future                    0.18.2             pyhd8ed1ab_6    conda-forge
gettext                   0.21.1               h0186832_0    conda-forge
giflib                    5.2.1                h27ca646_2    conda-forge
glib                      2.74.1               hb5ab8b9_0    conda-forge
glib-tools                2.74.1               hb5ab8b9_0    conda-forge
gst-plugins-base          1.21.1               h8b7775e_1    conda-forge
gstreamer                 1.21.1               hcb7b3dd_1    conda-forge
heapdict                  1.0.1                      py_0    conda-forge
hsluv                     5.0.2              pyh44b312d_0    conda-forge
icu                       70.1                 h6b3803e_0    conda-forge
idna                      3.4                pyhd8ed1ab_0    conda-forge
imagecodecs               2022.9.26       py310h24fba19_3    conda-forge
imageio                   2.22.0             pyhfa7a67d_0    conda-forge
imagesize                 1.4.1              pyhd8ed1ab_0    conda-forge
importlib-metadata        5.0.0              pyha770c72_1    conda-forge
importlib_resources       5.10.0             pyhd8ed1ab_0    conda-forge
ipykernel                 6.17.0             pyh736e0ef_0    conda-forge
ipython                   8.6.0              pyhd1c38e8_1    conda-forge
ipython_genutils          0.2.0                      py_1    conda-forge
ipywidgets                8.0.2              pyhd8ed1ab_1    conda-forge
jedi                      0.18.1             pyhd8ed1ab_2    conda-forge
jinja2                    3.1.2              pyhd8ed1ab_1    conda-forge
jpeg                      9e                   he4db4b2_2    conda-forge
jsonschema                4.16.0             pyhd8ed1ab_0    conda-forge
jupyter                   1.0.0           py310hbe9552e_7    conda-forge
jupyter_client            7.3.4              pyhd8ed1ab_0    conda-forge
jupyter_console           6.4.4              pyhd8ed1ab_0    conda-forge
jupyter_core              4.11.1          py310hbe9552e_1    conda-forge
jupyterlab_pygments       0.2.2              pyhd8ed1ab_0    conda-forge
jupyterlab_widgets        3.0.3              pyhd8ed1ab_0    conda-forge
jxrlib                    1.1                  h27ca646_2    conda-forge
kiwisolver                1.4.4           py310h2887b22_1    conda-forge
krb5                      1.19.3               hf9b2bbe_0    conda-forge
lcms2                     2.14                 h8193b64_0    conda-forge
lerc                      4.0.0                h9a09cb3_0    conda-forge
libaec                    1.0.6                hbdafb3b_0    conda-forge
libavif                   0.11.1               h3d80962_0    conda-forge
libblas                   3.9.0           16_osxarm64_openblas    conda-forge
libbrotlicommon           1.0.9                h1a8c8d9_8    conda-forge
libbrotlidec              1.0.9                h1a8c8d9_8    conda-forge
libbrotlienc              1.0.9                h1a8c8d9_8    conda-forge
libcblas                  3.9.0           16_osxarm64_openblas    conda-forge
libclang                  15.0.3          default_h9e54d93_0    conda-forge
libclang13                15.0.3          default_h7d574e7_0    conda-forge
libcurl                   7.86.0               hd538317_1    conda-forge
libcxx                    14.0.6               h2692d47_0    conda-forge
libdeflate                1.14                 h1a8c8d9_0    conda-forge
libedit                   3.1.20191231         hc8eb9b7_2    conda-forge
libev                     4.33                 h642e427_1    conda-forge
libffi                    3.4.2                h3422bc3_5    conda-forge
libgfortran               5.0.0           11_3_0_hd922786_25    conda-forge
libgfortran5              11.3.0              hdaf2cc0_25    conda-forge
libglib                   2.74.1               h14ed1c1_0    conda-forge
libiconv                  1.17                 he4db4b2_0    conda-forge
liblapack                 3.9.0           16_osxarm64_openblas    conda-forge
libllvm15                 15.0.3               h62b9111_1    conda-forge
libnghttp2                1.47.0               h232270b_1    conda-forge
libogg                    1.3.4                h27ca646_1    conda-forge
libopenblas               0.3.21          openmp_hc731615_3    conda-forge
libopus                   1.3.1                h27ca646_1    conda-forge
libpng                    1.6.38               h76d750c_0    conda-forge
libpq                     14.5                 h3f71257_1    conda-forge
libsodium                 1.0.18               h27ca646_1    conda-forge
libsqlite                 3.39.4               h76d750c_0    conda-forge
libssh2                   1.10.0               hb80f160_3    conda-forge
libtiff                   4.4.0                hfa0b094_4    conda-forge
libvorbis                 1.3.7                h9f76cd9_0    conda-forge
libwebp-base              1.2.4                h57fd34a_0    conda-forge
libxcb                    1.13              h9b22ae9_1004    conda-forge
libxml2                   2.10.3               h87b0503_0    conda-forge
libzlib                   1.2.13               h03a7124_4    conda-forge
libzopfli                 1.0.3                h9f76cd9_0    conda-forge
llvm-openmp               14.0.4               hd125106_0    conda-forge
locket                    1.0.0              pyhd8ed1ab_0    conda-forge
lz4                       4.0.2           py310ha6df754_0    conda-forge
lz4-c                     1.9.3                hbdafb3b_1    conda-forge
magicgui                  0.6.0              pyhd8ed1ab_0    conda-forge
markupsafe                2.1.1           py310h8e9501a_2    conda-forge
matplotlib-inline         0.1.6              pyhd8ed1ab_0    conda-forge
mistune                   2.0.4              pyhd8ed1ab_0    conda-forge
msgpack-python            1.0.4           py310h2887b22_1    conda-forge
mysql-common              8.0.31               hab468bb_0    conda-forge
mysql-libs                8.0.31               hea58576_0    conda-forge
napari                    0.4.16          pyh275ddea_0_pyqt    conda-forge
napari-console            0.0.6              pyhd8ed1ab_0    conda-forge
napari-plugin-engine      0.2.0              pyhd8ed1ab_2    conda-forge
napari-svg                0.1.6              pyhd8ed1ab_0    conda-forge
nbclient                  0.7.0              pyhd8ed1ab_0    conda-forge
nbconvert                 7.2.3              pyhd8ed1ab_0    conda-forge
nbconvert-core            7.2.3              pyhd8ed1ab_0    conda-forge
nbconvert-pandoc          7.2.3              pyhd8ed1ab_0    conda-forge
nbformat                  5.7.0              pyhd8ed1ab_0    conda-forge
ncurses                   6.3                  h07bb92c_1    conda-forge
nest-asyncio              1.5.6              pyhd8ed1ab_0    conda-forge
networkx                  2.8.7              pyhd8ed1ab_0    conda-forge
notebook                  6.4.12             pyha770c72_0    conda-forge
npe2                      0.6.1              pyhd8ed1ab_1    conda-forge
nspr                      4.32                 hbdafb3b_1    conda-forge
nss                       3.78                 h1483a63_0    conda-forge
numcodecs                 0.10.2          py310hc6dc59f_0    conda-forge
numpy                     1.23.4          py310h5d7c261_1    conda-forge
numpydoc                  1.5.0              pyhd8ed1ab_0    conda-forge
openjpeg                  2.5.0                h5d4e404_1    conda-forge
openssl                   1.1.1s               h03a7124_0    conda-forge
packaging                 21.3               pyhd8ed1ab_0    conda-forge
pandas                    1.5.1           py310h2b830bf_1    conda-forge
pandoc                    2.19.2               hce30654_1    conda-forge
pandocfilters             1.5.0              pyhd8ed1ab_0    conda-forge
parso                     0.8.3              pyhd8ed1ab_0    conda-forge
partd                     1.3.0              pyhd8ed1ab_0    conda-forge
pcre2                     10.37                hcf5f1cc_1    conda-forge
pep517                    0.12.0             pyhd8ed1ab_3    conda-forge
pexpect                   4.8.0              pyh1a96a4e_2    conda-forge
pickleshare               0.7.5                   py_1003    conda-forge
pillow                    9.2.0           py310h9337a76_3    conda-forge
pint                      0.20.1             pyhd8ed1ab_0    conda-forge
pip                       22.3               pyhd8ed1ab_0    conda-forge
pkgutil-resolve-name      1.3.10             pyhd8ed1ab_0    conda-forge
ply                       3.11                       py_1    conda-forge
pooch                     1.6.0              pyhd8ed1ab_0    conda-forge
prometheus_client         0.15.0             pyhd8ed1ab_0    conda-forge
prompt-toolkit            3.0.31             pyha770c72_0    conda-forge
prompt_toolkit            3.0.31               hd8ed1ab_0    conda-forge
psutil                    5.9.3           py310h8e9501a_1    conda-forge
psygnal                   0.3.5           py310hd23d0e8_0    conda-forge
pthread-stubs             0.4               h27ca646_1001    conda-forge
ptyprocess                0.7.0              pyhd3deb0d_0    conda-forge
pure_eval                 0.2.2              pyhd8ed1ab_0    conda-forge
pycparser                 2.21               pyhd8ed1ab_0    conda-forge
pydantic                  1.10.2          py310h8e9501a_1    conda-forge
pygments                  2.13.0             pyhd8ed1ab_0    conda-forge
pyopengl                  3.1.6              pyhd8ed1ab_1    conda-forge
pyopenssl                 22.1.0             pyhd8ed1ab_0    conda-forge
pyparsing                 3.0.9              pyhd8ed1ab_0    conda-forge
pyqt                      5.15.7          py310h7aaa74b_2    conda-forge
pyqt5-sip                 12.11.0         py310h0f1eb42_2    conda-forge
pyrsistent                0.18.1          py310h8e9501a_2    conda-forge
pysocks                   1.7.1              pyha2e5f31_6    conda-forge
python                    3.10.6          hbce4517_0_cpython    conda-forge
python-build              0.9.0              pyhd8ed1ab_0    conda-forge
python-dateutil           2.8.2              pyhd8ed1ab_0    conda-forge
python-fastjsonschema     2.16.2             pyhd8ed1ab_0    conda-forge
python_abi                3.10                    2_cp310    conda-forge
pytomlpp                  1.0.11          py310h2887b22_1    conda-forge
pytz                      2022.5             pyhd8ed1ab_0    conda-forge
pywavelets                1.3.0           py310hf1a086a_2    conda-forge
pyyaml                    6.0             py310h8e9501a_5    conda-forge
pyzmq                     24.0.1          py310hc407298_1    conda-forge
qt-main                   5.15.6               hf3dd84c_1    conda-forge
qtconsole-base            5.3.2              pyha770c72_0    conda-forge
qtpy                      2.2.1              pyhd8ed1ab_0    conda-forge
readline                  8.1.2                h46ed386_0    conda-forge
requests                  2.28.1             pyhd8ed1ab_1    conda-forge
rich                      12.6.0             pyhd8ed1ab_0    conda-forge
scikit-image              0.19.3          py310h2b830bf_2    conda-forge
scipy                     1.9.3           py310ha0d8a01_1    conda-forge
send2trash                1.8.0              pyhd8ed1ab_0    conda-forge
setuptools                65.5.0             pyhd8ed1ab_0    conda-forge
shellingham               1.5.0              pyhd8ed1ab_0    conda-forge
sip                       6.7.3           py310h0f1eb42_0    conda-forge
six                       1.16.0             pyh6c4a22f_0    conda-forge
snappy                    1.1.9                h39c3846_1    conda-forge
snowballstemmer           2.2.0              pyhd8ed1ab_0    conda-forge
sortedcontainers          2.4.0              pyhd8ed1ab_0    conda-forge
soupsieve                 2.3.2.post1        pyhd8ed1ab_0    conda-forge
sphinx                    5.3.0              pyhd8ed1ab_0    conda-forge
sphinxcontrib-applehelp   1.0.2                      py_0    conda-forge
sphinxcontrib-devhelp     1.0.2                      py_0    conda-forge
sphinxcontrib-htmlhelp    2.0.0              pyhd8ed1ab_0    conda-forge
sphinxcontrib-jsmath      1.0.1                      py_0    conda-forge
sphinxcontrib-qthelp      1.0.3                      py_0    conda-forge
sphinxcontrib-serializinghtml 1.1.5              pyhd8ed1ab_2    conda-forge
sqlite                    3.39.4               h2229b38_0    conda-forge
stack_data                0.6.0              pyhd8ed1ab_0    conda-forge
superqt                   0.3.8              pyhd8ed1ab_0    conda-forge
tblib                     1.7.0              pyhd8ed1ab_0    conda-forge
tensorstore               0.1.27                   pypi_0    pypi
terminado                 0.17.0             pyhd1c38e8_0    conda-forge
tifffile                  2022.10.10         pyhd8ed1ab_0    conda-forge
tinycss2                  1.2.1              pyhd8ed1ab_0    conda-forge
tk                        8.6.12               he1e0b03_0    conda-forge
toml                      0.10.2             pyhd8ed1ab_0    conda-forge
tomli                     2.0.1              pyhd8ed1ab_0    conda-forge
toolz                     0.12.0             pyhd8ed1ab_0    conda-forge
tornado                   6.1             py310hf8d0d8f_3    conda-forge
tqdm                      4.64.1             pyhd8ed1ab_0    conda-forge
traitlets                 5.5.0              pyhd8ed1ab_0    conda-forge
typer                     0.6.1              pyhd8ed1ab_0    conda-forge
typing-extensions         4.4.0                hd8ed1ab_0    conda-forge
typing_extensions         4.4.0              pyha770c72_0    conda-forge
tzdata                    2022f                h191b570_0    conda-forge
urllib3                   1.26.11            pyhd8ed1ab_0    conda-forge
vispy                     0.10.0          py310he2d1965_0    conda-forge
wcwidth                   0.2.5              pyh9f0ad1d_2    conda-forge
webencodings              0.5.1                      py_1    conda-forge
wheel                     0.37.1             pyhd8ed1ab_0    conda-forge
widgetsnbextension        4.0.3              pyhd8ed1ab_0    conda-forge
wrapt                     1.14.1          py310h8e9501a_1    conda-forge
xorg-libxau               1.0.9                h27ca646_0    conda-forge
xorg-libxdmcp             1.1.3                h27ca646_0    conda-forge
xz                        5.2.6                h57fd34a_0    conda-forge
yaml                      0.2.5                h3422bc3_2    conda-forge
zarpaint                  0.1.1.dev27+gfc48307           dev_0    <develop>
zarr                      2.13.3             pyhd8ed1ab_0    conda-forge
zeromq                    4.3.4                hbdafb3b_1    conda-forge
zfp                       1.0.0                hb6e4faa_3    conda-forge
zict                      2.2.0              pyhd8ed1ab_0    conda-forge
zipp                      3.10.0             pyhd8ed1ab_0    conda-forge
zlib-ng                   2.0.6                he4db4b2_0    conda-forge
zstd                      1.5.2                h8128057_4    conda-forge

@DragaDoncila
Copy link

@GenevieveBuckley yeah the paint event hasn't actually been released yet, so this only works with main - and will soon work with 0.4.17 when it's released in the next few days

@GenevieveBuckley
Copy link
Contributor

Had a quick look at this again and it functions well for 2d slices in a 3d volume, provided that the slice annotations overlap sufficiently (and that last part is a limitation of the algorithm we chose, as discussed previously).

I'm a lot less concerned that I was before about the usefulness of this in cases where a user needs to edit already generated labels. It turns out all you need to do is click "Start Interpolation", then click once with the paintbrush inside the already existing labels on the first and last slices, and then it will interpolate between them. So there's no need to worry about re-drawing edges correctly, which is the thing I was worried would be time consuming and difficult to do. 🎉

@GenevieveBuckley
Copy link
Contributor

Here's a test I wrote annotating 2D slices in a 3D volume

from napari.layers import Labels
import numpy as np
from skimage.draw import ellipse

from zarpaint._interpolate_labels import interpolate_between_slices

label_id = 2
arraysize = 512
slice_index_1 = 0
slice_index_2 = 10
# First label slice
coords_1 = ellipse(arraysize//2, arraysize//2,  # row, column (center coordinates)
                   arraysize//6, arraysize//6,  # r_radius, c_radius (ellipse radii)
                   shape=(arraysize, arraysize))
label_slice_1 = np.zeros(shape).astype(int)
label_slice_1[coords_1] = label_id
# Second label slice
coords_2 = ellipse(arraysize//2, arraysize//2,  # row, column (center coordinates)
                   arraysize//5, arraysize//3,  # r_radius, c_radius (ellipse radii)
                   shape=(arraysize, arraysize))
label_slice_2 = np.zeros(shape).astype(int)
label_slice_2[coords_2] = label_id
# Create labels for interpolation
labels = np.zeros((11, arraysize, arraysize)).astype(int)
labels[slice_index_1] = label_slice_1
labels[slice_index_2] = label_slice_2
labels_layer = Labels(labels)

# Check all intermediate label slices contain only zero
for labels_slice in labels_layer.data[1:-1]:
    assert np.max(labels_slice) == 0
# Check the expected number of non-zero pixels exist now 
assert np.count_nonzero(labels_layer.data[1:-1]) == 0

# Interpolate intermediate slices
interpolate_between_slices(labels_layer, slice_index_1, slice_index_2, label_id, interp_dim=0)

# Check all intermediate label slices now contain non-zero pixels
for labels_slice in labels_layer.data[1:-1]:
    assert np.max(labels_slice) == label_id
# Check the expected number of non-zero pixels exist now
assert np.count_nonzero(labels_layer.data[1:-1]) == 315045

@GenevieveBuckley
Copy link
Contributor

And here's a similar test, extended to a 4d array using ellispoid shapes. I've cut this down to interpolate across only three intermediate 3d volumes, so it runs in a reasonable amount of time (my %%timeit results: 1.6 s ± 37.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each))

from napari.layers import Labels
import numpy as np
from skimage.draw import ellipse

from zarpaint._interpolate_labels import interpolate_between_slices


label_id = 2
arraysize = 100
slice_index_1 = 0
slice_index_2 = 4
# First label slice
ellipse_1 = ellipsoid(20, 35, 25) * label_id
padding = np.array((arraysize, arraysize, arraysize)) - np.array(ellipse_1.shape)
pad_width = [(i//2, i//2 + 1) for i in padding]
label_slice_1 = np.pad(ellipse_1, pad_width)
# Second label slice
ellipse_2 = ellipsoid(28, 33, 40) * label_id
padding = np.array((arraysize, arraysize, arraysize)) - np.array(ellipse_2.shape)
pad_width = [(i//2, i//2 + 1) for i in padding]
label_slice_2 = np.pad(ellipse_2, pad_width)
# Create labels for interpolation
labels = np.zeros((5, arraysize, arraysize, arraysize)).astype(int)
labels[slice_index_1] = label_slice_1
labels[slice_index_2] = label_slice_2
labels_layer = Labels(labels)

# Check all intermediate label slices contain only zero
for labels_slice in labels_layer.data[1:-1]:
    assert np.max(labels_slice) == 0
# Check the expected number of non-zero pixels exist now 
assert np.count_nonzero(labels_layer.data[1:-1]) == 0

# Interpolate intermediate slices
interpolate_between_slices(labels_layer, slice_index_1, slice_index_2, label_id, interp_dim=0)

# Check all intermediate label slices now contain non-zero pixels
for labels_slice in labels_layer.data[1:-1]:
    assert np.max(labels_slice) == label_id
# Check the expected number of non-zero pixels exist now
assert np.count_nonzero(labels_layer.data[1:-1]) == 297885

@jni
Copy link
Owner

jni commented Dec 2, 2022

Wow, super cool @GenevieveBuckley, thanks for those tests! @jamesyan-git do you want to implement them and then we can merge this? 🎉

@jamesyan-git
Copy link
Contributor Author

Look amazing, I will add this now. I'll also include some that I've been writing but forgot to push.

@jni
Copy link
Owner

jni commented Dec 2, 2022

@jamesyan-git it looks like there's some bits that are still not tested — check out the link for the "codecov/patch" failed check. It's things to do with the viewer widget itself. You can test them by calling viewer.window.add_plugin_dock_widget (from memory — there's a function like that somewhere in the hierarchy). Then the widget is returned and you can call particular methods in it.

@jamesyan-git
Copy link
Contributor Author

Thanks Juan! I'm working on covering all the lines now.


if slice_index_1 > slice_index_2:
slice_index_1, slice_index_2 = slice_index_2, slice_index_1
layer_data = np.asarray(label_layer.data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line needs to be removed. (I assume it's here because you were debugging something, but we can't have an entire full size volume read into memory).

We should replace the following two lines with:

    slice_1 = np.take(label_layer.data, slice_index_1, axis=interp_dim)
    slice_2 = np.take(label_layer.data, slice_index_2, axis=interp_dim)

@jamesyan-git
Copy link
Contributor Author

hey @jni, I'm not sure why the macos tests are failing. any ideas?

@GenevieveBuckley
Copy link
Contributor

hey @jni, I'm not sure why the macos tests are failing. any ideas?

Looking at the log, it looks like there was problem during Run GabrielBB/xvfb-action@v1

It seems that github action is deprecated (see here, and recommends switching to https://github.com/coactions/setup-xvfb. So give that a go, just try swapping it over in the gihutb actions workflow files and see what happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants