Skip to content

Commit

Permalink
Add in ImageJ2 -> napari colormap conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
gselzer committed Sep 29, 2022
1 parent ff2f0f3 commit add77a3
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 22 deletions.
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies:
- labeling >= 0.1.12
- magicgui >= 0.5.1
- napari
- numpy
- openjdk=8
- pyimagej >= 1.2.0
# Project from source
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ install_requires =
confuse
labeling >= 0.1.12
napari
numpy
magicgui >= 0.5.1
pyimagej >= 1.2.0

Expand Down
8 changes: 8 additions & 0 deletions src/napari_imagej/java.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,10 @@ def SuperEllipsoid(self):
def Dataset(self):
return "net.imagej.Dataset"

@blocking_import
def DatasetView(self):
return "net.imagej.display.DatasetView"

@blocking_import
def DefaultROITree(self):
return "net.imagej.roi.DefaultROITree"
Expand All @@ -450,6 +454,10 @@ def DefaultROITree(self):
def ImageDisplay(self):
return "net.imagej.display.ImageDisplay"

@blocking_import
def ImgPlus(self):
return "net.imagej.ImgPlus"

@blocking_import
def Mesh(self):
return "net.imagej.mesh.Mesh"
Expand Down
56 changes: 53 additions & 3 deletions src/napari_imagej/types/converters/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,48 @@
and napari Images
"""

from typing import Any

from imagej.dims import _has_axis
from jpype import JArray, JByte
from napari.layers import Image
from napari.utils.colormaps import Colormap
from numpy import ones
from scyjava import Priority

from napari_imagej.java import ij, jc
from napari_imagej.types.converters import py_to_java_converter
from napari_imagej.types.converters import java_to_py_converter, py_to_java_converter


@java_to_py_converter(
predicate=lambda obj: ij().convert().supports(obj, jc.DatasetView),
priority=Priority.VERY_HIGH + 1,
)
def _dataset_view_to_image(image: Any) -> Image:
view = ij().convert().convert(image, jc.DatasetView)
# Construct a dataset from the data
data = ij().py.from_java(view.getData().getImgPlus().getImg())
name = view.getData().getName()
if view.getColorTables().size() > 0:
cmap = _color_table_to_colormap(view.getColorTables().get(0))
return Image(data=data, name=name, colormap=cmap)
return Image(data=data, name=name)


def _can_convert_img_plus(obj: Any):
can_convert = ij().convert().supports(obj, jc.ImgPlus)
has_axis = _has_axis(obj)
return can_convert and has_axis


@java_to_py_converter(predicate=_can_convert_img_plus, priority=Priority.VERY_HIGH)
def _dataset_to_image(image: Any) -> Image:
imp = ij().convert().convert(image, jc.ImgPlus)
# Construct a dataset from the data
data = ij().py.from_java(imp.getImg())
name = imp.getName()
cmap = imp.getColorTable(0)
return Image(data=data, name=name, colormap=cmap)


@py_to_java_converter(
Expand All @@ -23,13 +58,13 @@ def _image_to_dataset(image: Image) -> "jc.Dataset":
dataset.setName(image.name)
# Add color table, if the image uses a custom colormap
if image.colormap.name != "gray":
color_table = _colormap_to_colorTable(image.colormap)
color_table = _colormap_to_color_table(image.colormap)
dataset.initializeColorTables(1)
dataset.setColorTable(color_table, 0)
return dataset


def _colormap_to_colorTable(cmap: Colormap):
def _colormap_to_color_table(cmap: Colormap):
"""
Converts a napari Colormap into a SciJava ColorTable.
:param cmap: The napari Colormap
Expand All @@ -47,3 +82,18 @@ def _colormap_to_colorTable(cmap: Colormap):
j_values[i][j] = value if value < 128 else value - 256

return jc.ColorTable8(j_values)


def _color_table_to_colormap(ctable: "jc.ColorTable"):
"""
Converts a SciJava ColorTable into a napari Colormap.
:param ctable: The SciJava ColorTable
:return: An "equivalent" napari Colormap
"""
components = ctable.getComponentCount()
bins = ctable.getLength()
data = ones((bins, 4), dtype=float)
for component in range(components):
for bin in range(bins):
data[bin, component] = float(ctable.get(component, bin)) / 255.0
return Colormap(colors=data)
32 changes: 13 additions & 19 deletions src/napari_imagej/widgets/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,36 +205,30 @@ def get_chosen_layer(self) -> None:
# grab the chosen name
name = choices["data"]
# grab the chosen image
i = names.index(name)
image = ij().py.from_java(images[i])
# if the conversion is already a layer, add it directly
if isinstance(image, Layer):
image.name = name
self.viewer.add_layer(image)
# otherwise, try to coerce it into an Image layer
elif ij().py._is_arraylike(image):
self.viewer.add_image(data=image, name=name)
# if we can't coerce it, give up
else:
raise ValueError(f"{image} cannot be displayed in napari!")
view = (
ij().get("org.scijava.display.DisplayService").getDisplay(name).get(0)
)
self._add_image_from_display_view(view)

def get_active_layer(self) -> None:
# Choose the active Dataset
image = ij().get("net.imagej.display.ImageDisplayService").getActiveDataset()
if image is None:
# Choose the active DatasetView
view = ij().get("net.imagej.display.ImageDisplayService").getActiveDatasetView()
if view is None:
log_debug("There is no active window to export to napari")
return
self._add_image_from_display_view(view)

def _add_image_from_display_view(self, view: "jc.DatasetView"):
# Get the stuff needed for a new layer
py_image = ij().py.from_java(image)
name = ij().object().getName(image)
py_image = ij().py.from_java(view)
# Create and add the layer
if isinstance(py_image, Layer):
py_image.name = name
self.viewer.add_layer(py_image)
elif ij().py._is_arraylike(py_image):
name = ij().object().getName(view)
self.viewer.add_image(data=py_image, name=name)
else:
raise ValueError(f"{image} cannot be displayed in napari!")
raise ValueError(f"{view} cannot be displayed in napari!")


class GUIButton(QPushButton):
Expand Down

0 comments on commit add77a3

Please sign in to comment.