Skip to content
Snippets Groups Projects
Commit 70910f2d authored by s214735's avatar s214735
Browse files

some changes and some new additions

parent 5640d292
No related branches found
No related tags found
1 merge request!150Draft: Notebook update
%% Cell type:markdown id: tags:
 
## Local thickness notebook
 
%% Cell type:markdown id: tags:
 
This notebook shows an example of how to determine the **local thickness** of an object in either 2D and 3D using the `qim3d` library. The local thickness at a point within the object is defined as the radius of the largest circle (2D) or sphere (3D) that contains the point and is inside the object.
 
%% Cell type:markdown id: tags:
 
In the following, the local thickness is computed for three examples:
 
* **Example 1**: 2D image of blobs
* **Example 2**: 3D volume of shell
* **Example 3**: 3D volume of cement
 
The local thickness algorithm is applied by using the `qim3d.processing.local_thickness` function, which expects a binary image/volume. If the input is not already binary, then it will be binarized automatically using Otsu's thresholding method. The `qim3d.processing.local_thickness` function returns a 2D or 3D Numpy array representing the local thickness of the input image/volume.
 
%% Cell type:markdown id: tags:
 
#### **Example 1**: Local thickness of 2D image
This example uses a 2D image of blobs (256 x 256), which can be acquired from `qim3d.examples.blobs_256x256`.
 
The image is loaded using the `load` method from the `io` module. This is followed by a calculation of the local thicknes of the image.
 
%% Cell type:code id: tags:
 
``` python
import qim3d
# Load 2D image of blobs
img = qim3d.io.load('../../qim3d/examples/blobs_256x256.png', progress_bar=False)
# Load 2D grayscale image of blobs
img = qim3d.io.load('../../qim3d/examples/blobs_256x256.png', progress_bar=False, log_memory=False)
 
# Compute the local thickness of the blobs
img_lt = qim3d.processing.local_thickness(img, visualize=True)
img_lt = qim3d.processing.local_thickness(img, visualize=True, )
```
 
%% Output
 
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[1], line 3
1 import qim3d
2 # Load 2D image of blobs
----> 3 img = qim3d.io.load('../../qim3d/examples/blobs_256x256.png', progress_bar=False)
5 # Compute the local thickness of the blobs
6 img_lt = qim3d.processing.local_thickness(img, visualize=True)
File ~/qim3d/qim3d/io/_loading.py:841, in load(path, virtual_stack, dataset_name, return_metadata, contains, progress_bar, force_load, dim_order, **kwargs)
839 data = loader.load(path)
840 else:
--> 841 data = loader.load(path)
843 def log_memory_info(data):
844 mem = Memory()
File ~/qim3d/qim3d/io/_loading.py:730, in DataLoader.load(self, path)
728 suggestion = similar_paths[0] # Get the closest match
729 message = f"Invalid path. Did you mean '{suggestion}'?"
--> 730 raise ValueError(repr(message))
731 else:
732 raise ValueError("Invalid path")
ValueError: "Invalid path. Did you mean '../../qim3d/examples/fly_150x256x256.tif'?"
Input image is not binary. It will be binarized using Otsu's method with threshold: 69
 
%% Cell type:markdown id: tags:
 
#### **Example 2**: Local thickness of 3D volume
This example uses a 3D volume of a shell (225 x 128 x 128), which can be acquired from `qim3d.examples.shell_225x128x128`.
 
Likewise, the local thickness is calculated after. Since this image is 3D, there is a slider to evaluate the local thickness through the layers of the volume.
 
%% Cell type:code id: tags:
 
``` python
# Import 3D volume of shell
vol = qim3d.examples.shell_225x128x128
 
# Compute the local thickness of shell
vol_lt = qim3d.processing.local_thickness(vol, visualize=True, axis=0)
```
 
%% Output
 
Input image is not binary. It will be binarized using Otsu's method with threshold: 65
 
 
%% Cell type:markdown id: tags:
 
#### **Example 3**: Local thickness of (binary) 3D volume
This example uses a 3D volume of cement (128 x 128 x 128), which can be acquired from `qim3d.examples.cement_128x128x128`.
 
For the previous two examples, the original image/volume was passed directly to the `qim3d.processing.local_thickness` function, which automatically binarized the input prior to computing the local thickness.
 
For this example, the original volume will instead first be manually binarized with the `qim3d.detection.blobs` method (see details in the documentation for `qim3d.detection.blobs`). Then the binarized volume (i.e. mask) will be passed to the `qim3d.processing.local_thickness` function, which can then directly compute the local thickness.
 
%% Cell type:markdown id: tags:
 
**Importing, filtering and visualizing volume**
 
First the image is loaded and filtered.
 
%% Cell type:code id: tags:
 
``` python
# Import 3D volume of cement
vol = qim3d.examples.cement_128x128x128
 
# Visualize slices of the original cement volume
fig1 = qim3d.viz.slices_grid(vol, num_slices=5, display_figure=True)
 
# Apply Gaussian filter to the cement volume
vol_filtered = qim3d.filters.gaussian(vol, sigma=2)
 
# Visualize slices of the filtered cement volume
fig2 = qim3d.viz.slices_grid(vol_filtered, num_slices=5, display_figure=True)
```
 
%% Output
 
 
 
%% Cell type:markdown id: tags:
 
**Detecting blobs in volume, creating binary mask**
 
Now blobs are detected in the volume, generating both blobs and a binary mask. The mask is visualized to get a sense of the structure.
 
%% Cell type:code id: tags:
 
``` python
# Detect blobs in the volume
blobs, mask = qim3d.detection.blobs(
vol_filtered,
min_sigma=1,
max_sigma=8,
threshold=0.001,
overlap=0.1,
background="bright"
)
 
# Visualize the blob mask
qim3d.viz.slicer(mask)
```
 
%% Output
 
Bright background selected, volume will be inverted.
 
interactive(children=(IntSlider(value=64, description='Slice', max=127), Output()), layout=Layout(align_items=…
 
%% Cell type:markdown id: tags:
 
**Computing local thickness**
 
Lastly, the local thickness of the mask is calculated. Once again, since the volume is 3D, a slider allows for exploration of the local thickness.
 
%% Cell type:code id: tags:
 
``` python
# Compute the local thickness of cement (input: binary mask)
mask_lt = qim3d.processing.local_thickness(mask, visualize=True, axis=0)
```
 
%% Output
 
......
%% Cell type:markdown id: tags:
## OME-Zarr notebook
This notebook will demonstrate the `qim3d` functionalities that specifically target the OME-Zarr file format.
OME-Zarr is a cloud-native, multi-dimensional file format optimized for storing and analyzing large-scale volumetric imaging data. It leverages the Zarr storage framework, which organizes data in a chunked, hierarchical structure, enabling efficient random access to specific regions without loading entire datasets into memory. The format supports multi-resolution storage, allowing visualization and analysis at different levels of detail, improving performance for large datasets. OME-Zarr stores metadata in JSON format following the Open Microscopy Environment (OME) model, ensuring interoperability across a wide range of bioimaging tools. Additionally, its compatibility with modern data science libraries like Dask and Xarray allows for scalable parallel processing, making it an ideal choice for applications in microscopy, medical imaging, and machine learning.
First we will fetch a large data file, which we can save to the OME-Zarr file type. Here we will use the `io.Downloader` class. First we define the variable, and then we evaluate what data we would like to download, by visualizing the options with the 'help' command.
%% Cell type:code id: tags:
``` python
import qim3d
downloader = qim3d.io.Downloader()
help(downloader)
```
%% Output
Help on Downloader in module qim3d.io._downloader object:
class Downloader(builtins.object)
| Class for downloading large data files available on the [QIM data repository](https://data.qim.dk/).
|
| Attributes:
| folder_name (str or os.PathLike): Folder class with the name of the folder in <https://data.qim.dk/>
|
| Syntax for downloading and loading a file is `qim3d.io.Downloader().{folder_name}.{file_name}(load_file=True)`
|
| ??? info "Overview of available data"
| Below is a table of the available folders and files on the [QIM data repository](https://data.qim.dk/).
|
| Folder name | File name | File size
| ------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------
| `Coal` | `CoalBrikett` <br> `CoalBrikett_Zoom` <br> `CoalBrikettZoom_DOWNSAMPLED` | 2.23 GB <br> 3.72 GB <br> 238 MB
| `Corals` | `Coral_1` <br> `Coral_2` <br> `Coral2_DOWNSAMPLED` <br> `MexCoral` | 2.26 GB <br> 2.38 GB <br> 162 MB <br> 2.23 GB
| `Cowry_Shell` | `Cowry_Shell` <br> `Cowry_DOWNSAMPLED` | 1.82 GB <br> 116 MB
| `Crab` | `HerrmitCrab` <br> `OkinawaCrab` | 2.38 GB <br> 1.86 GB
| `Deer_Mandible` | `Animal_Mandible` <br> `DeerMandible_DOWNSAMPLED` <br> | 2.79 GB <br> 638 MB
| `Foam` | `Foam` <br> `Foam_DOWNSAMPLED` <br> `Foam_2` <br> `Foam_2_zoom` | 3.72 GB <br> 238 MB <br> 3.72 GB <br> 3.72 GB
| `Hourglass` | `Hourglass` <br> `Hourglass_4X_80kV_Air_9s_1_97um` <br> `Hourglass_longexp_rerun` | 3.72 GB <br> 1.83 GB <br> 3.72 GB
| `Kiwi` | `Kiwi` | 2.86 GB
| `Loofah` | `Loofah` <br> `Loofah_DOWNSAMPLED` | 2.23 GB <br> 143 MB
| `Marine_Gastropods` | `MarineGatropod_1` <br> `MarineGastropod1_DOWNSAMPLED` <br> `MarineGatropod_2` <br> `MarineGastropod2_DOWNSAMPLED` | 2.23 GB <br> 143 MB <br> 2.60 GB <br> 166 MB
| `Mussel` | `ClosedMussel1` <br> `ClosedMussel1_DOWNSAMPLED` | 2.23 GB <br> 143 MB
| `Oak_Branch` | `Oak_branch` <br> `OakBranch_DOWNSAMPLED` | 2.38 GB <br> 152 MB
| `Okinawa_Forams` | `Okinawa_Foram_1` <br> `Okinawa_Foram_2` | 1.84 GB <br> 1.84 GB
| `Physalis` | `Physalis` <br> `Physalis_DOWNSAMPLED` | 3.72 GB <br> 238 MB
| `Raspberry` | `Raspberry2` <br> `Raspberry2_DOWNSAMPLED` | 2.97 GB <br> 190 MB
| `Rope` | `FibreRope1` <br> `FibreRope1_DOWNSAMPLED` | 1.82 GB <br> 686 MB
| `Sea_Urchin` | `SeaUrchin` <br> `Cordatum_Shell` <br> `Cordatum_Spine` | 2.60 GB <br> 1.85 GB <br> 183 MB
| `Snail` | `Escargot` | 2.60 GB
| `Sponge` | `Sponge` | 1.11 GB
|
| Example:
| ```python
| import qim3d
|
| downloader = qim3d.io.Downloader()
| data = downloader.Cowry_Shell.Cowry_DOWNSAMPLED(load_file=True)
|
| qim3d.viz.slicer_orthogonal(data, color_map="magma")
| ```
| ![cowry shell](assets/screenshots/cowry_shell_slicer.gif)
| ![cowry shell](../../assets/screenshots/cowry_shell_slicer.gif)
|
| Methods defined here:
|
| __init__(self)
| Initialize self. See help(type(self)) for accurate signature.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables
|
| __weakref__
| list of weak references to the object
%% Cell type:markdown id: tags:
After deciding to use the coral data, we fetch the data. We use the 'load_file' argument to load it while downloading it. Additionally, we can use the vizualisation tool `slicer_orthogonal` too explore the volume from three different axes.
After deciding to use the okinawa crab volume, we fetch the data. We use the 'load_file' argument to load it while downloading it. Additionally, we can use the vizualisation tool `slicer_orthogonal` too explore the volume from three different axes.
%% Cell type:code id: tags:
``` python
vol = downloader.Corals.Coral2_DOWNSAMPLED(load_file=True)
qim3d.viz.slicer_orthogonal(vol, color_map="magma")
vol = downloader.Crab.OkinawaCrab(load_file=True)
```
%% Output
File already downloaded:
/home/s214735/qim3d/docs/notebooks/Corals/Coral2_DOWNSAMPLED.tif
/home/s214735/qim3d/docs/notebooks/Crab/OkinawaCrab.tif
Loading Coral2_DOWNSAMPLED.tif
Loading OkinawaCrab.tif
Loaded shape: (500, 400, 400)
Loaded shape: (995, 1014, 992)
Using virtual stack
HBox(children=(interactive(children=(IntSlider(value=250, description='Z', max=499), Output()), layout=Layout(…
%% Cell type:markdown id: tags:
Attempting to visualize the volume in a three-dimensional space will require a lot of computing power due to the size of the volume. However using the OME-Zarr data type, we can visualize it in chunks. Additionally we can save it in the .zarr format.
First we export the file using the `export_ome_zarr` method.
First we export the file using the `export_ome_zarr` method. We set the downsample rate to 3, such that we have different scales of the volume.
%% Cell type:code id: tags:
``` python
qim3d.io.export_ome_zarr(
'coral.zarr',
'crab.zarr',
vol,
chunk_size=200,
downsample_rate=2,
downsample_rate=3,
replace=True)
```
%% Output
Exporting data to OME-Zarr format at coral.zarr
Exporting data to OME-Zarr format at crab.zarr
Number of scales: 3
Calculating the multi-scale pyramid
- Scale 0: (500, 400, 400)
- Scale 1: (250, 200, 200)
- Scale 2: (125, 100, 100)
- Scale 0: (995, 1014, 992)
- Scale 1: (332, 338, 331)
- Scale 2: (111, 113, 110)
Writing data to disk
All done!
%% Cell type:markdown id: tags:
We can then use the `chunks` method to visualize the chunks from the volume. Here we have both options for exploring the volume slices or the entire 3D object.
We can then use the `chunks` method to visualize the chunks from the volume. Here we have both options for exploring the volume slices or the entire 3D object. Additionally we can change the view dimension and the scale of the volume.
%% Cell type:code id: tags:
``` python
qim3d.viz.chunks('coral.zarr')
qim3d.viz.chunks('crab.zarr')
```
%% Output
%% Cell type:markdown id: tags:
After looking at the object, we see that some of it is obstructed by background noise. Therefore we attempt to remove that with a threshold, followed by another export and visualization of the volume:
If we wish to continue working on a downsampled version of the volume, we can load it back in using `import_ome_zarr`. Here we use the `scale` argument to decide what scale we with to import. By writing 'lowest', we can get the lowest resolution, and by writing 0 or 'highest' we can get the highest resolution. In this case we want the volume at scale 1 along with the highest resolution:
%% Cell type:code id: tags:
``` python
vol_t = vol > 30000
qim3d.io.export_ome_zarr(
'coral_threshold.zarr',
vol_t,
chunk_size=200,
downsample_rate=2,
replace=True)
qim3d.viz.chunks('coral_threshold.zarr')
vol_lowscale = qim3d.io.import_ome_zarr('crab.zarr', scale=1)
vol_highscale = qim3d.io.import_ome_zarr('crab.zarr', scale='highest')
```
%% Output
Exporting data to OME-Zarr format at coral_threshold.zarr
Number of scales: 3
Calculating the multi-scale pyramid
- Scale 0: (500, 400, 400)
- Scale 1: (250, 200, 200)
- Scale 2: (125, 100, 100)
Writing data to disk
/home/s214735/miniconda3/envs/qim3d-env/lib/python3.11/site-packages/zarr/creation.py:614: UserWarning: ignoring keyword argument 'read_only'
compressor, fill_value = _kwargs_compat(compressor, fill_value, kwargs)
Data contains 3 scales:
- Scale 0: (995, 1014, 992)
- Scale 1: (332, 338, 331)
- Scale 2: (111, 113, 110)
Loading scale 1 with shape (332, 338, 331)
Data contains 3 scales:
- Scale 0: (995, 1014, 992)
- Scale 1: (332, 338, 331)
- Scale 2: (111, 113, 110)
Loading scale 0 with shape (995, 1014, 992)
%% Cell type:markdown id: tags:
All done!
Now we can visually inspect the volume at different scales. In this case, we can separate the first 256 voxels:
%% Cell type:code id: tags:
``` python
vol_low = vol_lowscale[0:256, 0:256, 0:256]
vol_high = vol_highscale[256:512, 256:512, 256:512]
```
%% Cell type:markdown id: tags:
For next time the volume is to be used, we can import it easily using the `import_ome_zarr` method:
Then we can visualize the volume along the three primary axes.
%% Cell type:code id: tags:
``` python
vol_t = qim3d.io.import_ome_zarr('coral_threshold.zarr')
qim3d.viz.slicer_orthogonal(vol_low)
```
%% Output
Data contains 3 scales:
- Scale 0: (500, 400, 400)
- Scale 1: (250, 200, 200)
- Scale 2: (125, 100, 100)
Loading scale 0 with shape (500, 400, 400)
HBox(children=(interactive(children=(IntSlider(value=128, description='Z', max=255), Output()), _dom_classes=(…
%% Cell type:code id: tags:
``` python
qim3d.viz.slicer_orthogonal(vol_high)
```
%% Output
HBox(children=(interactive(children=(IntSlider(value=128, description='Z', max=255), Output()), _dom_classes=(…
......
qim3d/examples/blobs_256x256.png

18.5 KiB

......@@ -771,6 +771,7 @@ def load(
progress_bar: bool = True,
force_load: bool = False,
dim_order: tuple = (2, 1, 0),
log_memory: bool = True,
**kwargs,
) -> np.ndarray:
"""
......@@ -852,6 +853,7 @@ def load(
log.warning("The file format does not contain metadata")
if not virtual_stack:
if log_memory:
log_memory_info(data)
else:
# Only log if file type is not a np.ndarray, i.e., it is some kind of memmap object
......@@ -861,6 +863,7 @@ def load(
log.info("Using virtual stack")
else:
log.warning("Virtual stack is not supported for this file format")
if log_memory:
log_memory_info(data)
return data
......
......@@ -389,7 +389,7 @@ def slicer(
continuous_update=True,
)
slicer_obj = widgets.interactive(_slicer, slice_positions=position_slider)
slicer_obj.layout = widgets.Layout(align_items="flex-start")
#slicer_obj.layout = widgets.Layout(align_items="flex-start")
return slicer_obj
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment