From bacf849c19f0f92774c1369ec16cd5635de3caa9 Mon Sep 17 00:00:00 2001 From: AnniekStok Date: Tue, 30 Jan 2024 17:52:46 +0100 Subject: [PATCH 1/5] replace ijm macro activity with the metaphase image --- .../volume_slicing_act1_imagej-gui.md | 4 +- .../volume_slicing_act1_imagej-macro.ijm | 67 +++++++++++-------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/_includes/volume_slicing/volume_slicing_act1_imagej-gui.md b/_includes/volume_slicing/volume_slicing_act1_imagej-gui.md index 16062e9f..b9dbe04f 100644 --- a/_includes/volume_slicing/volume_slicing_act1_imagej-gui.md +++ b/_includes/volume_slicing/volume_slicing_act1_imagej-gui.md @@ -1,6 +1,6 @@ - Open a 3D image -- Use `Imaeg > Properties` to check for anisotropic voxel sizes -- Use `Image > Stacks > Orthogonal views` to view the data in XY, XZ and YZ planes +- Use `Image > Properties` to check for anisotropic voxel sizes +- Use `Image > Stacks > Orthogonal views` to view the data in XY, XZ and YZ planes - Understand how the anisotropy is dealt with - Use `Image > Stacks > Reslice` to resample the data, exploring the below options to deal with anisotropy - `Output spacing` diff --git a/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm b/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm index 1da35060..f764f81c 100644 --- a/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm +++ b/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm @@ -1,32 +1,45 @@ -// This macro opens the head image stack and reslices it to view it from different angles (side, front, top and diagonal view) -// and then selects slices corresponding to Z=60, X=135, and Y=160. -// Close other open images -run("Close All"); +// open image stack +open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_16bit_calibrated__dna_metaphase.tif"); -// open head image stack -open("http://imagej.net/images/t1-head.zip"); -rename("Head viewed from the side"); -run("Duplicate...", "duplicate range=60"); -rename("Head Z=60"); +// explore the dimensions +width = getWidth(); +height = getHeight(); +depth = nSlices(); +print("Original Image Dimensions: Width = " + width + ", Height = " + height + ", Depth = " + depth); -// Reslice the head image stack to view the head from the front and from the top, and select the slices for X=135 and Y=160 in the orginal view. -selectWindow("Head viewed from the side"); -run("Reslice [/]...", "output=1.500 start=Left rotate"); // view head from the front -rename("Head viewed from the front"); -run("Duplicate...", "duplicate range=135-135"); -rename("Head X=135"); +// reslice YZ with interpolation +run("Reslice [/]...", "output=0.300 start=Left flip rotate"); +rename("YZ view"); +width = getWidth(); +height = getHeight(); +depth = nSlices(); +print("Image Dimensions YZ view: Width = " + width + ", Height = " + height + ", Depth = " + depth); -selectWindow("Head viewed from the side"); -run("Reslice [/]...", "output=1.500 start=Top rotate"); // view head from the top -rename("Head viewed from the top"); -run("Duplicate...", "duplicate range=160-160"); -rename("Head Y=160"); +// reslice XZ with interpolation +selectImage("xyz_16bit_calibrated__dna_metaphase.tif"); +run("Reslice [/]...", "output=0.300 start=Top"); +rename("XZ view"); +width = getWidth(); +height = getHeight(); +depth = nSlices(); +print("Image Dimensions XZ view: Width = " + width + ", Height = " + height + ", Depth = " + depth); -// Rotate the head stack that is viewed from the side and reslice to obtain diagonal view -selectWindow("Head viewed from the side"); -run("Duplicate...", "duplicate"); -run("Rotate... ", "angle=45 grid=1 interpolation=Bilinear enlarge stack"); // rotate the stack -run("Reslice [/]...", "output=1.500 start=Top rotate"); -rename("Head in diagonal view"); +// reslice YZ without interpolation +selectImage("xyz_16bit_calibrated__dna_metaphase.tif"); +run("Reslice [/]...", "output=0.300 start=Left flip rotate avoid"); +rename("YZ view"); +width = getWidth(); +height = getHeight(); +depth = nSlices(); +print("Image Dimensions YZ view WITHOUT interpolation: Width = " + width + ", Height = " + height + ", Depth = " + depth); -run("Tile"); +// reslice XZ with interpolation +selectImage("xyz_16bit_calibrated__dna_metaphase.tif"); +run("Reslice [/]...", "output=0.300 start=Top avoid"); +rename("XZ view"); +width = getWidth(); +height = getHeight(); +depth = nSlices(); +print("Image Dimensions XZ view WITHOUT interpolation: Width = " + width + ", Height = " + height + ", Depth = " + depth); + +run("Tile") From 4015ab0778e5ebba38c9d333550e596252e18576 Mon Sep 17 00:00:00 2001 From: AnniekStok Date: Thu, 14 Mar 2024 12:07:22 +0100 Subject: [PATCH 2/5] add python-napari version for reslicing and visualizing anisotropy --- .../volume_slicing_act1_python-napari.py | 29 +++++++++++++++++++ _modules/volume_slicing.md | 6 ++-- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 _includes/volume_slicing/volume_slicing_act1_python-napari.py diff --git a/_includes/volume_slicing/volume_slicing_act1_python-napari.py b/_includes/volume_slicing/volume_slicing_act1_python-napari.py new file mode 100644 index 00000000..8c3b5d54 --- /dev/null +++ b/_includes/volume_slicing/volume_slicing_act1_python-napari.py @@ -0,0 +1,29 @@ +# !First start Napari and drag and drop the image (https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_16bit_calibrated__dna_metaphase.tif) in the Napari viewer. + +# Access the 3D array in the image layer +d = viewer.layers[0].data # assuming the image is in the first layer +shape = d.shape +print("Image shape:", shape) + +# Compare the non-scaled non-scaled image to the scaled image. You can also use the 3D view to better appreciate the dimensions. +voxel_dims = (0.300, 0.1377745, 0.1377745) # original voxel dimensions in µm, in order ZYX +scaled_voxel_dims = [1 / voxel_dims[0] * v for v in voxel_dims] # rescaling the voxel dimensions to maintain proportions but display with a z-step of 1. +print("New voxel dimensions scaled relative to original", scaled_voxel_dims) +viewer.add_image(d, name="Scaled to physical world dimensions", scale=scaled_voxel_dims) # Note that the scaled image layer contains the exact same data as the non-scaled image, but is only visualized differently to show the correct proportions. + +# Create 2D slices (YX, ZX, and ZY) +mid_z_slice_ind = shape[0] // 2 +mid_y_slice_ind = shape[1] // 2 +mid_x_slice_ind = shape[2] // 2 + +viewer.add_image(d[mid_z_slice_ind], name=f"z={mid_z_slice_ind}") +viewer.add_image(d[mid_z_slice_ind], name=f"scaled: z={mid_z_slice_ind}", scale = scaled_voxel_dims[1:]) +viewer.add_image(d[:, mid_y_slice_ind, :], name=f"y={mid_y_slice_ind}") +viewer.add_image(d[:, mid_y_slice_ind, :], name=f"scaled: y={mid_y_slice_ind}", scale = [scaled_voxel_dims[0], scaled_voxel_dims[2]]) +viewer.add_image(d[:, :, mid_x_slice_ind], name=f"x={mid_x_slice_ind}") +viewer.add_image(d[:, :, mid_x_slice_ind], name=f"scaled: x={mid_x_slice_ind}", scale = scaled_voxel_dims[:2]) + +# View in grid mode side by side +viewer.grid.stride = 1 +viewer.grid.shape = (-1, 2) +viewer.grid.enabled=True diff --git a/_modules/volume_slicing.md b/_modules/volume_slicing.md index 85862efb..c183ce14 100644 --- a/_modules/volume_slicing.md +++ b/_modules/volume_slicing.md @@ -17,13 +17,13 @@ concept_map: > V["Volume data"] --> S("Slicing") V --- A["Anisotropic"] S --> M["2D image"] - M -.- A + M -.- A figure: /figures/volume_slicing.png -figure_legend: "Extracting 2-D slices from a 3-D volume, e.g. to be visualised on a computer monitor." +figure_legend: "Extracting 2-D slices from a 3-D volume, e.g. to be visualised on a computer monitor." multiactivities: - - ["volume_slicing/volume_slicing_act1.md", [["ImageJ GUI", "volume_slicing/volume_slicing_act1_imagej-gui.md", "markdown"], ["ImageJ Macro", "volume_slicing/volume_slicing_act1_imagej-macro.ijm", "java"], ["ImageJ Jython", "volume_slicing/volume_slicing_act1_imagej-jython.py", "python"]]] + - ["volume_slicing/volume_slicing_act1.md", [["ImageJ GUI", "volume_slicing/volume_slicing_act1_imagej-gui.md", "markdown"], ["ImageJ Macro", "volume_slicing/volume_slicing_act1_imagej-macro.ijm", "java"], ["ImageJ Jython", "volume_slicing/volume_slicing_act1_imagej-jython.py", "python"], ["Python Napari", "volume_slicing/volume_slicing_act1_python-napari.py", "python"]]] assessment: > From c6bb725735b9f2abcca853f7a328b666799ab005 Mon Sep 17 00:00:00 2001 From: AnniekStok Date: Thu, 14 Mar 2024 12:12:38 +0100 Subject: [PATCH 3/5] remove the jython exercise from the markdown file --- _modules/volume_slicing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_modules/volume_slicing.md b/_modules/volume_slicing.md index c183ce14..ff542572 100644 --- a/_modules/volume_slicing.md +++ b/_modules/volume_slicing.md @@ -23,7 +23,7 @@ figure: /figures/volume_slicing.png figure_legend: "Extracting 2-D slices from a 3-D volume, e.g. to be visualised on a computer monitor." multiactivities: - - ["volume_slicing/volume_slicing_act1.md", [["ImageJ GUI", "volume_slicing/volume_slicing_act1_imagej-gui.md", "markdown"], ["ImageJ Macro", "volume_slicing/volume_slicing_act1_imagej-macro.ijm", "java"], ["ImageJ Jython", "volume_slicing/volume_slicing_act1_imagej-jython.py", "python"], ["Python Napari", "volume_slicing/volume_slicing_act1_python-napari.py", "python"]]] + - ["volume_slicing/volume_slicing_act1.md", [["ImageJ GUI", "volume_slicing/volume_slicing_act1_imagej-gui.md", "markdown"], ["ImageJ Macro", "volume_slicing/volume_slicing_act1_imagej-macro.ijm", "java"], ["Python Napari", "volume_slicing/volume_slicing_act1_python-napari.py", "python"]]] assessment: > From 59bc4558626c7ce52487891384fecc996ac143df Mon Sep 17 00:00:00 2001 From: AnniekStok <32863964+AnniekStok@users.noreply.github.com> Date: Mon, 18 Mar 2024 09:38:18 +0100 Subject: [PATCH 4/5] Update volume_slicing_act1_imagej-macro.ijm --- _includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm b/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm index f764f81c..9a1f12b7 100644 --- a/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm +++ b/_includes/volume_slicing/volume_slicing_act1_imagej-macro.ijm @@ -1,4 +1,4 @@ -// open image stack +// open volumetric image open("https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_16bit_calibrated__dna_metaphase.tif"); // explore the dimensions From 4db8a0eecc0f8de2e835f7bd352e24f970f21fe3 Mon Sep 17 00:00:00 2001 From: AnniekStok <32863964+AnniekStok@users.noreply.github.com> Date: Mon, 18 Mar 2024 09:40:48 +0100 Subject: [PATCH 5/5] Update volume_slicing_act1_python-napari.py implenting Tischi's comments --- .../volume_slicing_act1_python-napari.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/_includes/volume_slicing/volume_slicing_act1_python-napari.py b/_includes/volume_slicing/volume_slicing_act1_python-napari.py index 8c3b5d54..8bfcfe14 100644 --- a/_includes/volume_slicing/volume_slicing_act1_python-napari.py +++ b/_includes/volume_slicing/volume_slicing_act1_python-napari.py @@ -1,20 +1,21 @@ # !First start Napari and drag and drop the image (https://github.com/NEUBIAS/training-resources/raw/master/image_data/xyz_16bit_calibrated__dna_metaphase.tif) in the Napari viewer. # Access the 3D array in the image layer -d = viewer.layers[0].data # assuming the image is in the first layer -shape = d.shape +image = viewer.layers[0].data # assuming the image is in the first layer +shape = image.shape print("Image shape:", shape) -# Compare the non-scaled non-scaled image to the scaled image. You can also use the 3D view to better appreciate the dimensions. +# Compare the non-scaled image to the scaled image. You can also use the 3D view to better appreciate the dimensions. voxel_dims = (0.300, 0.1377745, 0.1377745) # original voxel dimensions in µm, in order ZYX -scaled_voxel_dims = [1 / voxel_dims[0] * v for v in voxel_dims] # rescaling the voxel dimensions to maintain proportions but display with a z-step of 1. +scale_factor = 1 / voxel_dims[0] +scaled_voxel_dims = [voxel_dims[0] * scale_factor, voxel_dims[1] * scale_factor, voxel_dims[2] * scale_factor] # rescaling the voxel dimensions to maintain proportions but display with a z-step of 1. print("New voxel dimensions scaled relative to original", scaled_voxel_dims) viewer.add_image(d, name="Scaled to physical world dimensions", scale=scaled_voxel_dims) # Note that the scaled image layer contains the exact same data as the non-scaled image, but is only visualized differently to show the correct proportions. # Create 2D slices (YX, ZX, and ZY) -mid_z_slice_ind = shape[0] // 2 -mid_y_slice_ind = shape[1] // 2 -mid_x_slice_ind = shape[2] // 2 +mid_z_slice_ind = int(shape[0] / 2) +mid_y_slice_ind = int(shape[1] / 2) +mid_x_slice_ind = int(shape[2] / 2) viewer.add_image(d[mid_z_slice_ind], name=f"z={mid_z_slice_ind}") viewer.add_image(d[mid_z_slice_ind], name=f"scaled: z={mid_z_slice_ind}", scale = scaled_voxel_dims[1:])