Skip to content

Commit

Permalink
Merge branch 'master' into python-add-lineplot-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
k-dominik authored Apr 28, 2024
2 parents 14db11f + 134410e commit 72632f0
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 123 deletions.
59 changes: 26 additions & 33 deletions _includes/lut/lut_act1_skimage_napari.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,58 @@
# %% [markdown]
# # Explore LUTs
# %%
# Using different Lookup Tables (LUTs) in napari

# %%
# Instantiate the napari viewer
import napari
viewer = napari.Viewer()

# %%
# Read the image
# Read an image and its metadata
from OpenIJTIFF import open_ij_tiff
image, axes, scales, units = open_ij_tiff('https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_high_dynamic_range.tif')

# %% [markdown]
# ### Napari GUI alternative to load data
# Drag and drop and rename the layer (alternative for loading data)\
# Change name of layer `viewer.layers[0].name = 'image_grayscale'` \
# Get the data as numpy array `image = viewer.layers['image_grayscale'].data`

# %%
# Check image type and values
import numpy as np
print(image.dtype, np.min(image), np.max(image))
image, axes, scales, units = open_ij_tiff("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_high_dynamic_range.tif")

# %%
# View the intensity image as grayscale
viewer.add_image(image, name='image_grayscale', colormap='gray')

# %%
# Change brightness and contrast
# Change contrast programatically
# Jupyter: Use TAB to to practice auto-completion when entering below command
viewer.layers['image_grayscale'].contrast_limits=(100, 175)

# %% [markdown]
# **Napari GUI** explore different contrast limits

# %%
# View the intensity image as grayscale
viewer.add_image(image, name='image_grayscale2', colormap='gray')

# %% [markdown]
# **Napari GUI** visualize images side by side\
# **Napari GUI** change brightness and contrast to visualize dim nuclei
# Napari: Change the contrast in the GUI
# Napari: Right click on "contrast limits" to see the value range

# %%
# Check available colormap
print(list(napari.utils.colormaps.AVAILABLE_COLORMAPS))
# Add the image a second time
viewer.add_image(image, name='image_grayscale2', colormap='gray')

# %%
# Change colormap
viewer.add_image(image, name='image_turbo', colormap='turbo')

# %% [markdown]
# **Napari GUI** explore different LUTs
# Napari: Visualize images side by side by toggling on the "Grid mode"
# Napari: Change contrast in one image to see the dim nuclei

# %%
# Extract image data from the layers
image_grayscale = viewer.layers['image_grayscale'].data
image_grayscale2 = viewer.layers['image_grayscale2'].data

# %%
# Compare raw data
# Check that changing the LUT did not change the data
print(image_grayscale[0:5,0:5])
print(image_grayscale2[0:5,0:5])

# %%
# Check whether all pixels of the two images are identical
print((image_grayscale == image_grayscale2).all())

# %%
# Check available LUTs (colormaps)
print(list(napari.utils.colormaps.AVAILABLE_COLORMAPS))

# %%
# Add the image again with a multi-color LUT
viewer.add_image(image, name='image_turbo', colormap='turbo')

# %%
# Napari: Explore different LUTs using the GUI
29 changes: 17 additions & 12 deletions _includes/lut/lut_act2_skimage_napari.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
# %% [markdown]
# # Configure LUTs
# %%
# Show two images with the same LUT settings

# %%
# Instantiate the napari viewer
import napari
viewer = napari.Viewer()

# %%
# Read the image
# Read the images
from OpenIJTIFF import open_ij_tiff
image_control, axes_control, scales_control, units_control = open_ij_tiff('https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_calibrated_16bit__nuclear_protein_control.tif')
image_treated, axes_treated, scales_treated, units_treated = open_ij_tiff('https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_calibrated_16bit__nuclear_protein_treated.tif')
image_control, *_ = open_ij_tiff('https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_calibrated_16bit__nuclear_protein_control.tif')
image_treated, *_ = open_ij_tiff('https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_calibrated_16bit__nuclear_protein_treated.tif')

# %%
# View the intensity image as grayscale
# View the image as grayscale
viewer.add_image(image_control, name='control', colormap='gray')
viewer.add_image(image_treated, name='treated', colormap='gray')

# %% [markdown]
# **Napari GUI** Show images side by side \
# **Napari GUI** Inspect possible consistent limits for both images
# %%
# Napari: Toggle grid mode on to the see images side by side
# Napari: Check the contrast limits for the two images

# %%
# Check the contrast limits programatically
print(viewer.layers['control'].contrast_limits)
print(viewer.layers['treated'].contrast_limits)

# %%
# Apply limits to both images
viewer.layers['control'].contrast_limits=(0, 1024)
viewer.layers['treated'].contrast_limits=(0, 1024)
# Apply the same contrast to both images
viewer.layers['control'].contrast_limits=(0, 2500)
viewer.layers['treated'].contrast_limits=(0, 2500)
8 changes: 8 additions & 0 deletions _includes/pixels/pixels_3d_image_inspection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h4 id="3d"><a href="#2d">Inspect a 3D image</a></h4>

Explore the content of a 3D image:
- Essentially follow the instructions for inspecting a 2D image (see above actitvity)
- Depending on the software that you are using it may be more or less convenient to deal with the 3rd dimension

Example data:
- [xyz_8bit__mri_head.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_8bit__mri_head.tif)
45 changes: 45 additions & 0 deletions _includes/pixels/pixels_3d_image_inspection_skimage_napari.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# %%
# 3D image inspection using skimage and napari

# %%
# Load an image
from OpenIJTIFF import open_ij_tiff
image_url = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_8bit__mri_head.tif"
image, axes, *_ = open_ij_tiff(image_url)

# %%
# Inspect the image shape
print(image.shape)

# %%
# Inspect the image axes
print(axes)

# %%
# Inspect all image pixel values, and appreciate that this is not useful for larger 3D data
print(image)

# %%
# Create a napari viewer and add the image
from napari.viewer import Viewer
napari_viewer = Viewer()
napari_viewer.add_image(image)

# %%
# Napari:
# - However with the mouse over the image and observe the pixel indices and values
# - Use the slider to change the position of the 3rd dimension

# %%
# Extract the pixels that belong to the tip of the nose
print(image[1, 9:19, 89:102])

# %%
# Compute the image min and max
print(image.min(), image.max())

# %%
# Compute the image histogram
import matplotlib.pyplot as plt
import numpy as np
plt.hist(image.flatten(), bins=np.arange(image.min(), image.max() + 1));
18 changes: 12 additions & 6 deletions _includes/pixels/pixels_act1.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<h4 id="2d"><a href="#2d">Inspect a 2D image</a></h4>
- Open image: [xy_8bit__nuclei_noisy_different_intensity.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_noisy_different_intensity.tif)
- Explore different ways to inspect pixel values and indices, e.g.,
- Examine image dimensions
- Examine individual (or a range of) pixel values
- Plot line profiles
- Compute and plot pixel value histograms

Explore the content of a 2D image:
- Examine image dimensions
- Examine individual (or a range of) pixel values
- Plot line profiles
- Compute and plot pixel value histograms
- This is, e.g., important for [image thresholding](https://neubias.github.io/training-resources/binarization/index.html)
- Compute pixel value statistics, such as min, max
- This is, e.g., important for checking for [intensity clipping](https://neubias.github.io/training-resources/datatypes/index.html)

Example data:
- [xy_8bit__nuclei_noisy_different_intensity.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_noisy_different_intensity.tif)
93 changes: 57 additions & 36 deletions _includes/pixels/pixels_act1_skimage_napari.py
Original file line number Diff line number Diff line change
@@ -1,72 +1,93 @@
# %% [markdown]
# ## Inspect a 2D image
# %%
# 2D image inspection using skimage and napari


# %%
# Load the image
# You can also load a local image by providing the path to the file
# Load an image
from OpenIJTIFF import open_ij_tiff
image_url = "https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_noisy_different_intensity.tif"
image, axes, scales, units = open_ij_tiff(image_url)
image, *_ = open_ij_tiff(image_url)

# %%
# Create a new napari viewer.
from napari.viewer import Viewer
napari_viewer = Viewer()
# Inspect all image pixel values
print(image)

# %% [markdown]
# ### Code completion and help in Jupyter notebook
# * **Code completion** type `napari_viewer.` and press `TAB`
# * **Help** type `napari_viewer.add_image` and press `SHIFT-TAB` this will open a help associated to the add_image method/command
# %%
# Inspect the image shape
print(image.shape)

# %%
# Create a napari viewer
from napari.viewer import Viewer
napari_viewer = Viewer()

# %%
# Jupyter notebook exercise:
# Code completion: Type `napari_viewer.` and press `TAB`
# Get help: Type `napari_viewer.add_image` and press `SHIFT-TAB`

# %%
# Add an image to the napari_viewer.
# Add an image to the napari_viewer
napari_viewer.add_image(image)

# %% [markdown]
# ### Alternative loading of data
# **Napari GUI** drag and drop image from browser\
# rename the layer for convenience\
# `napari_viewer.layers[0].name = 'image'`
# Get the data as numpy array\
# `image = napari_viewer.layers['image'].data`
# %%
# Pixel value inspection in napari:
# However with the mouse over the image and observe the pixel indices and values

# %%
# Print image shape
print(image.shape)
# Inspect the pixel at the top left corner
print(image[0, 0])

# %%
# Print the image pixel values.
print(image)
# Inspect the pixel at the bottom right corner
print(image[49, 58])
print(image.shape[0], image.shape[1])
print(image[image.shape[0]-1, image.shape[1]-1))

# %%
# Top left corner is [y, x] = [r, c] = [0, 0]
print(image[0, 0])
# Fetch a pixel value from the background
# Beware the index order: [y, x] = [r, c]
print(image[4, 8])

# %%
# [y, x] = [r, c] = [1, 0]
print(image[1, 0])
# Fetch a pixel value from within an object
print(image[31, 42])

# %%
# [y, x] = [r, c] = [0, 2]
print(image[0, 2])
# Extract a line of pixel values across the objects
print(image[20,:])

# %% [markdown]
# **Napari GUI** Explore the napari-plot-profile plugin (optional)
# %%
# Napari:
# Use the plot profile plugin to inspect a line of pixel values

# %%
# Extract one object as a square of pixel values
print(image[7:30,10:26])

# %%
import numpy as np
# Compute min and max.
# Compute the image min and max
print(image.min(), image.max())

# %%
# Compute the image histogram
import matplotlib.pyplot as plt
# Use matplotlib to quickly plot a histogram.
import numpy as np
plt.hist(image.flatten(), bins=np.arange(image.min(), image.max() + 1));

# %%
# Most frequent pixel value (the mode)
# Compute the most frequent pixel value (the mode)
from scipy.stats import mode
mode(image, axis = None, keepdims = True)

# %%
# Napari:
# Alternative loading of data
# Remove the currently shown image
# Drag and drop image from browser onto napari
# Rename the layer to: image

# %%
# Fetch the image data from napari and check its shape
image = napari_viewer.layers['image'].data
print(image.shape)
44 changes: 9 additions & 35 deletions _modules/pixels.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,15 @@ multiactivities:
- ["pixels/pixels_act1.md", [["ImageJ GUI", "pixels/pixels_act1_imagejgui.md"], ["skimage napari", "pixels/pixels_act1_skimage_napari.py"], ["MATLAB", "pixels/pixels_act1_matlab.m"]]]
- ["pixels/collagen_inspection.md", [["ImageJ GUI", "pixels/collagen_inspection_imagejgui.md"]]]

assessment: >
### 2-D image inspection
Open image
[xy_8bit__nuclei_noisy_different_intensity.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_noisy_different_intensity.tif).
Hint: For certain exercises the inspection of the histogram will help
1. What is the value of the pixel at the indices (x=20,y=20)?
1. What is the highest value in the image?
1. What is the most frequently occurring value in the image?
1. Where is this pixel with the indices (x=0,y=0)? Why is this potentially confusing?
1. How many pixels does this image have in the x direction?
1. What is the highest pixel index in the x direction?
1. If you were to rotate the image by 90 degrees, would it change the image histogram?
> ## Solution
> 1. 82
> 1. 129
> 1. 55
> 1. Top left; normally x/y coordinate systems have their origin at the bottom left
> 1. 59
> 1. 58
> 1. No, the gray value histogram is independent of the pixel locations
{: .solution}
### 3-D image inspection
Open image: [xyz_8bit__mri_head.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_8bit__mri_head.tif)
1. What is the value of the voxel at the indices (x=93,y=124,z=13)?
1. Which is the highest value in the image?
> ## Solution
> 1. 47
> 1. 255
{: .solution}
exercises:
assessment: |
### Answer the question
1. If someome gives you a 2D image file and tells you to measure the value of the pixel at the indices `(7,8)` without telling you which programming language to use. Is that a precise enough instruction? If not, how many different pixels could that actually refer to?
> ## Solution
> 1. Unfortunately this instruction is not precise enough and, in practice it could refer to four different pixels, depending on whether this is meant to be zero or one-based indexing and depending whether this is row or column-major ordering. See [here for more details](https://en.wikipedia.org/wiki/Row-_and_column-major_order).
{: .solution}
learn_next:
- "[Lookup tables](../lut)"
Expand Down
Loading

0 comments on commit 72632f0

Please sign in to comment.