Skip to content

Commit

Permalink
Add image registration module skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
tischi committed Jul 1, 2024
1 parent 6f12376 commit 89932be
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 41 deletions.
10 changes: 6 additions & 4 deletions _includes/datatypes/inspect_12bit_saturation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<h4 id="saturation_8bit"><a href="#saturation_8bit">Find saturated pixels in an 8-bit image</a></h4>
<h4 id="saturation_12bit"><a href="#saturation_12bit">Find saturated pixels in an 12-bit image</a></h4>

Saturation, i.e. pixel value at the upper end of the datatype, is a typical problem in fluorescence microscopy images.
Saturation, i.e. pixel value at the upper end of the datatype, is a typical problem in fluorescence microscopy images.

- Open [xy_8bit__nuclei_intensity_clipping_issue_a.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_8bit__nuclei_intensity_clipping_issue_a.tif)
- Observe that this is an 8-bit image with saturation issues, i.e. many pixels of value 255
Inspecting 12-bit images, as acquired by some camera based systems, is particularly tricky, because 12-bit images are typically represented as 16-bit images, both on disk and within analysis software.

- Open [xy_12bit__saturated_plant.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xy_12bit__saturated_plant.tif)
- Observe that while this opens as 16-bit image there are many pixels at the highest value of 4095, which is the maximum of a 12-bit image.
1 change: 1 addition & 0 deletions _includes/image_registration/act01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h4 id=act_ref><a href=#act_ref>Activity title</a></h4>
Empty file.
Empty file.
6 changes: 3 additions & 3 deletions _includes/projections/projections_act1.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
- Perform a maximum projection along the z-axis to "see all spots at once"
- Discuss under which circumstances the number of dots in the projection equals the total number of spots in 3-D
- Also perform a **sum** projection and discuss why this is may be better than a maximum projection in terms of quantifying the total signal contained in the spots
- Understand that the data type of a sum projection typically needs to be adapted
- Project along the x and y axis
- Understand the projections along the x or y axis typically yield an anisotropic images (due to an initial xy/z anisotropy)
- Understand that the data type of a sum projection typically needs to be "larger" than the input data
- Project along the x or y axis
- Understand that projections along the x or y axis typically yield anisotropic images (due to an initial xy/z anisotropy)
- Resample or rescale the x and y projections for correct appearance in physical space

![](/figures/projections_activity.png)
Expand Down
4 changes: 1 addition & 3 deletions _includes/projections/projections_act1_skimage_napari.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@
# %%
# Compute sum projection along z-axis
# and display it in napari
# - Napari: There is an an issue rendering the sum projection pixel values:
# some high values appear dark. More details and a possible work-around is given at
# the end of this script.
# - Napari: There is an an issue rendering the sum projection pixel values: some high values appear dark. More details and a possible work-around is given at the end of this script.
sum_z_image = np.sum(image, axis=0)
viewer.add_image(sum_z_image, scale=[scales[1], scales[2]])

Expand Down
5 changes: 3 additions & 2 deletions _includes/spatial_calibration/spatial_calibration_act1.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<h4 id='explore3D'><a href="#explore3D">Explore the spatial calibration of a 3D image</a></h4>
- Open an image and find the spatial calibration metadata; understand why this can be important.
- Show how to measure the Euclidian calibrated distances of pixels in 2D and 3D.
- Open an image and find the spatial calibration metadata
- Understand that this is important for both rendering and measurements
- Measure Euclidian calibrated distances in the image
- Example image: [xyz_8bit__mitotic_plate_calibrated.tif](https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_8bit__mitotic_plate_calibrated.tif)
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# Spatial image calibration
#
# Requirements:
# - [skimage and napari](https://neubias.github.io/training-resources/tool_installation/index.html#skimage_napari)
# - https://neubias.github.io/training-resources/tool_installation/index.html#skimage_napari

# %%
# Import python packages.
# Import python packages
from OpenIJTIFF import open_ij_tiff
import numpy as np
from napari.viewer import Viewer
Expand All @@ -23,64 +23,55 @@

# %%
# View the image in napari
# - Observe that the 3D rendering does not reflect the real shape
# of the metaphase chromosomes in this image
Viewer().add_image(image)

# %%
# Napari GUI:
# - In order to inspect the image from "the side", change the axes order
# using the corresponding button; observe that additional data
# layers have been added to deal with the voxel_size anisotropy of this image
# - Look at the image in 3-D using the corresponding button;
# observe that the overall shape looks correct, thanks to the anisotropic scalings
# - Change the axes order to look at the image from the side using the corresponding button
# - Look at the image in 3-D using the corresponding button
# - Conclude that the physical shape does not look correct
# - Important: close this viewer before proceeding, not to confuse yourself

# %%
# Open a new napari and and now add the image with its voxel size as a "scale".
# - Note that we are using a new viewer because navigating
# both the scaled and unscaled image in the same viewer is tricky
# - Note that we are using a new viewer because navigating both the scaled and unscaled image in the same viewer is tricky
# - Again look at the image from the side and in 3-D
# - Observe that napari added interpolated data to make the image appear scaled
viewer = Viewer()
viewer.add_image(image, scale=voxel_size)


# %%
# Compute distances between points
# - In the next few steps we will computed distances between 3-D points
# In the next few steps we will compute distances between 3-D points

# %%
# Napari GUI:
# - Use the `New points layer button` to create a new points layer
# - Use `Add points` to add two points somewhere on the meta-phase plate

# %%
# Extract point coordinates
# observe that they are in unscaled voxel coordinates
# and thus not suited for measuring distances
# Extract the point coordinates
points = viewer.layers['Points'].data
print(points)
print(points) # unscaled => not very useful for physical measurements

# %%
# Scale the positions
scale = viewer.layers['Points'].scale
# Scale the points
scale = viewer.layers['Points'].scale # same as voxel_size
print("Points scale: ", scale)
print("Voxel size: ", voxel_size)

# %%
points_cal = points * scale
print("Points :\n", points)
print("Calibrated points :\n", points_cal)
print("Points:\n", points)
print("Calibrated points:\n", points_cal)

# %%
# Compute distance between points in voxel indices
# - Formula: sqrt( (z[1] - z[0])^2 + (y[1] - y[0])^2 + (x[1] - x[0])^2 )
# - Pythagoras: sqrt( (z1-z0)^2 + (y1-y0)^2 + (x1-x0)^2 )
diff_vector = points_cal[1] - points_cal[0]
print("diff_vector: ", diff_vector)
print("diff_vector:", diff_vector)

# %%
sqr_diff_vector = diff_vector**2
print("sqr_diff_vector: ", sqr_diff_vector)
print("sqr_diff_vector:", sqr_diff_vector)

# %%
distance = np.sqrt(sqr_diff_vector.sum())
print('distance:', distance)
print("distance:", distance)
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
)

# %%
# Inspect the image axes metadata
# Inspect the image metadata
print("Shape: ", image_2D.shape)
print("Axes: ", axes_image_2D)
print("Scale: ", voxel_size_image_2D)
Expand Down
42 changes: 42 additions & 0 deletions _modules/image_registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: Image registration
layout: module
tags: ["draft"]
prerequisites:
- "[Correlative image rendering](../correlative_image_rendering)"
- "?! A basic understanding of image transformations"
objectives:
- "Register one image to another"
motivation: |
TODO
concept_map: >
graph TD
T1("TODO1") --> T2("TODO2")
T2 --> T3("TODO3")
figure: /figures/image_registration.png
figure_legend: TODO

multiactivities:
- ["image_registration/act01.md", [["ImageJ GUI", "image_registration/act01_imagejgui.md"], ["skimage napari", "image_registration/act01_skimage_napari.py"]]]

assessment: >
### Fill in the blanks
1. TODO ___ .
1. TODO ___ .
> ## Solution
> 1. TODO
> 1. TODO
{: .solution}
learn_next:
- "[Automatic threshold for binarization](../auto_threshold)"

external_links:
- "[Wikipedia: Binary image](https://en.wikipedia.org/wiki/Binary_image)"
---

Binary file added figures/image_registration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 89932be

Please sign in to comment.