Skip to content
Snippets Groups Projects
Commit 447666f1 authored by fima's avatar fima :beers:
Browse files

slices_grid calls refactoring

parent 5505b582
No related branches found
No related tags found
1 merge request!139Refactoring v1.0 prep
This commit is part of merge request !139. Comments created here will be created in the context of that merge request.
%% Cell type:code id: tags:
``` python
import qim3d
```
%% Cell type:markdown id: tags:
### Blob detection notebook
%% Cell type:markdown id: tags:
This notebook shows how to do **blob detection** in a 3D volume using the `qim3d` library.
Blob detection is done by using the `qim3d.processing.blob_detection` method, which detects blobs by using the Difference of Gaussian (DoG) blob detection method, and returns two arrays:
- `blobs`: The blobs found in the volume stored as `(p, r, c, radius)`
- `binary_volume`: A binary mask of the volume with the blobs marked as `True`
%% Cell type:markdown id: tags:
### **Example 1**: Blob detection in cement volume
%% Cell type:markdown id: tags:
**Applying Gaussian filter to volume**
%% Cell type:code id: tags:
``` python
# Import 3D volume of cement
cement = qim3d.examples.cement_128x128x128
# Visualize slices of the original cement volume
qim3d.viz.slices(cement, n_slices = 5, show = True)
qim3d.viz.slices_grid(cement, n_slices = 5, show = True)
# Apply Gaussian filter to the cement volume
cement_filtered = qim3d.processing.gaussian(cement, sigma = 2)
# Visualize slices of the filtered cement volume
qim3d.viz.slices(cement_filtered)
qim3d.viz.slices_grid(cement_filtered)
```
%% Output
<Figure size 1000x200 with 5 Axes>
%% Cell type:markdown id: tags:
**Detecting blobs in volume**
%% Cell type:code id: tags:
``` python
# Detect blobs, and get binary mask
blobs, mask = qim3d.processing.blob_detection(
cement_filtered,
min_sigma=1,
max_sigma=8,
threshold=0.001,
overlap=0.1,
background="bright"
)
# Number of blobs found
print(f'Number of blobs found in the volume: {len(blobs)} blobs')
```
%% Output
Bright background selected, volume will be inverted.
Number of blobs found in the volume: 1813 blobs
%% Cell type:code id: tags:
``` python
# Visualize blobs on slices of cement volume
qim3d.viz.detection.circles(blobs, cement, alpha = 0.8, show = True, color = 'red')
```
%% Output
interactive(children=(IntSlider(value=64, description='Slice', max=127), Output()), layout=Layout(align_items=…
%% Cell type:markdown id: tags:
**Binary mask of detected blobs**
%% Cell type:code id: tags:
``` python
# Visualize binary mask
qim3d.viz.slicer(mask)
```
%% Output
interactive(children=(IntSlider(value=64, description='Slice', max=127), Output()), layout=Layout(align_items=…
......
%% Cell type:code id: tags:
 
``` python
import qim3d
```
 
%% Output
 
WARNING:root:Could not load CuPy: No module named 'cupy'
 
%% 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`.
 
%% Cell type:code id: tags:
 
``` python
# Import 2D image of blobs
blobs = qim3d.examples.blobs_256x256
 
# Compute the local thickness of the blobs
lt_blobs = qim3d.processing.local_thickness(blobs, visualize = True)
```
 
%% Output
 
Input image is not binary. It will be binarized using Otsu's method with threshold: 74
WARNING:qim3d:Input image is not binary. It will be binarized using Otsu's method with threshold: 74
 
 
%% 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`.
 
%% Cell type:code id: tags:
 
``` python
# Import 3D volume of shell
shell = qim3d.examples.shell_225x128x128
 
# Compute the local thickness of shell
lt_shell = qim3d.processing.local_thickness(shell, visualize = True, axis = 0)
```
 
%% Output
 
Input image is not binary. It will be binarized using Otsu's method with threshold: 65
WARNING:qim3d: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.processing.Blob.get_mask` method (see details in the documentation for `qim3d.processing.Blob`). 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**
 
%% Cell type:code id: tags:
 
``` python
# Import 3D volume of cement
cement = qim3d.examples.cement_128x128x128
 
# Visualize slices of the original cement volume
qim3d.viz.slices(cement, n_slices = 5, show = True)
qim3d.viz.slices_grid(cement, n_slices = 5, show = True)
 
# Apply Gaussian filter to the cement volume
cement_filtered = qim3d.processing.gaussian(cement, sigma = 2)
 
# Visualize slices of the filtered cement volume
qim3d.viz.slices(cement_filtered)
qim3d.viz.slices_grid(cement_filtered)
```
 
%% Output
 
 
<Figure size 1000x200 with 5 Axes>
 
%% Cell type:markdown id: tags:
 
**Detecting blobs in volume, creating binary mask**
 
%% Cell type:code id: tags:
 
``` python
# Initialize Blob detector
blob_detector = qim3d.processing.Blob(
min_sigma=1,
max_sigma=8,
threshold=0.001,
overlap=0.1,
background="bright"
)
 
# Detect blobs
cement_blobs = blob_detector.detect(cement_filtered)
 
# Get binary mask and visualize
cement_mask = blob_detector.get_mask()
qim3d.viz.slicer(cement_mask)
```
 
%% Output
 
interactive(children=(IntSlider(value=64, description='Slice', max=127), Output()), layout=Layout(align_items=…
 
%% Cell type:markdown id: tags:
 
**Computing local thickness**
 
%% Cell type:code id: tags:
 
``` python
# Compute the local thickness of cement (input: binary mask)
lt_cement = qim3d.processing.local_thickness(cement_mask, visualize = True, axis = 0)
```
 
%% Output
 
......
......@@ -114,7 +114,7 @@ This version focus on the increased usability of the `qim3d` library
- Online documentation available at [https://platform.qim.dk/qim3d](https://platform.qim.dk/qim3d)
- Virtual stacks also available for `txm` files
- Updated GUI launch pipeline
- New functionalities for `qim3d.viz.slices`
- New functionalities for `qim3d.viz.slices_grid`
- Introduction of `qim3d.processing.filters` 🎉
- Introduction of `qim3d.viz.vol` 🎉
......@@ -140,7 +140,7 @@ Includes new develoments toward the usability of the library, as well as its int
- For the local thicknes GUI, now it is possible to pass and receive numpy arrays instead of using the upload functionality.
- Improved data loader
- Now the extensions `tif`, `h5` and `txm` are supported.
- Added `qim3d.viz.slices` for easy slice visualization.
- Added `qim3d.viz.slices_grid` for easy slice visualization.
- U-net model creation
- Model availabe from `qim3d.models.UNet`
- Data augmentation class at `qim3d.utils.Augmentation`
......
......@@ -119,7 +119,7 @@ class Pipeline:
vol = qim3d.examples.fly_150x256x256
# Show original
qim3d.viz.slices(vol, axis=0, show=True)
qim3d.viz.slices_grid(vol, axis=0, show=True)
# Create filter pipeline
pipeline = Pipeline(
......@@ -134,7 +134,7 @@ class Pipeline:
vol_filtered = pipeline(vol)
# Show filtered
qim3d.viz.slices(vol_filtered, axis=0)
qim3d.viz.slices_grid(vol_filtered, axis=0)
```
![original volume](assets/screenshots/filter_original.png)
![filtered volume](assets/screenshots/filter_processed.png)
......
......@@ -52,7 +52,7 @@ def blob(
```python
# Visualize slices
qim3d.viz.slices(synthetic_blob, vmin = 0, vmax = 255, n_slices = 15)
qim3d.viz.slices_grid(synthetic_blob, vmin = 0, vmax = 255, n_slices = 15)
```
![synthetic_blob](assets/screenshots/synthetic_blob_slices.png)
......@@ -76,7 +76,7 @@ def blob(
```python
# Visualize slices
qim3d.viz.slices(vol, n_slices=15, axis=1)
qim3d.viz.slices_grid(vol, n_slices=15, axis=1)
```
![synthetic_blob_cylinder_slice](assets/screenshots/synthetic_blob_cylinder_slice.png)
......@@ -100,7 +100,7 @@ def blob(
```python
# Visualize
qim3d.viz.slices(vol, n_slices=15)
qim3d.viz.slices_grid(vol, n_slices=15)
```
![synthetic_blob_tube_slice](assets/screenshots/synthetic_blob_tube_slice.png)
"""
......
......@@ -255,7 +255,7 @@ def collection(
```python
# Visualize slices
qim3d.viz.slices(vol, n_slices=15)
qim3d.viz.slices_grid(vol, n_slices=15)
```
![synthetic_collection_cylinder](assets/screenshots/synthetic_collection_cylinder_slices.png)
......@@ -285,7 +285,7 @@ def collection(
```python
# Visualize slices
qim3d.viz.slices(vol, n_slices=15, axis=1)
qim3d.viz.slices_grid(vol, n_slices=15, axis=1)
```
![synthetic_collection_tube](assets/screenshots/synthetic_collection_tube_slices.png)
"""
......
......@@ -29,7 +29,7 @@ def remove_background(
import qim3d
vol = qim3d.examples.cement_128x128x128
qim3d.viz.slices(vol, vmin=0, vmax=255)
qim3d.viz.slices_grid(vol, vmin=0, vmax=255)
```
![operations-remove_background_before](assets/screenshots/operations-remove_background_before.png)
......@@ -37,7 +37,7 @@ def remove_background(
vol_filtered = qim3d.processing.operations.remove_background(vol,
min_object_radius=3,
background="bright")
qim3d.viz.slices(vol_filtered, vmin=0, vmax=255)
qim3d.viz.slices_grid(vol_filtered, vmin=0, vmax=255)
```
![operations-remove_background_after](assets/screenshots/operations-remove_background_after.png)
"""
......
......@@ -26,7 +26,7 @@ def watershed(bin_vol: np.ndarray, min_distance: int = 5) -> tuple[np.ndarray, i
vol = qim3d.examples.cement_128x128x128
binary = qim3d.processing.filters.gaussian(vol, sigma = 2)<60
qim3d.viz.slices(binary, axis=1)
qim3d.viz.slices_grid(binary, axis=1)
```
![operations-watershed_before](assets/screenshots/operations-watershed_before.png)
......@@ -34,7 +34,7 @@ def watershed(bin_vol: np.ndarray, min_distance: int = 5) -> tuple[np.ndarray, i
labeled_volume, num_labels = qim3d.processing.operations.watershed(binary)
cmap = qim3d.viz.colormaps.objects(num_labels)
qim3d.viz.slices(labeled_volume, axis = 1, cmap = cmap)
qim3d.viz.slices_grid(labeled_volume, axis = 1, cmap = cmap)
```
![operations-watershed_after](assets/screenshots/operations-watershed_after.png)
......
......@@ -52,14 +52,14 @@ def test_grid_pred():
# unit tests for slices function
def test_slices_numpy_array_input():
example_volume = np.ones((10, 10, 10))
fig = qim3d.viz.slices(example_volume, n_slices=1)
fig = qim3d.viz.slices_grid(example_volume, n_slices=1)
assert isinstance(fig, plt.Figure)
def test_slices_wrong_input_format():
input = "not_a_volume"
with pytest.raises(ValueError, match="Data type not supported"):
qim3d.viz.slices(input)
qim3d.viz.slices_grid(input)
def test_slices_not_volume():
......@@ -68,7 +68,7 @@ def test_slices_not_volume():
ValueError,
match="The provided object is not a volume as it has less than 3 dimensions.",
):
qim3d.viz.slices(example_volume)
qim3d.viz.slices_grid(example_volume)
def test_slices_wrong_position_format1():
......@@ -77,7 +77,7 @@ def test_slices_wrong_position_format1():
ValueError,
match='Position not recognized. Choose an integer, list of integers or one of the following strings: "start", "mid" or "end".',
):
qim3d.viz.slices(example_volume, position="invalid_slice")
qim3d.viz.slices_grid(example_volume, position="invalid_slice")
def test_slices_wrong_position_format2():
......@@ -86,7 +86,7 @@ def test_slices_wrong_position_format2():
ValueError,
match='Position not recognized. Choose an integer, list of integers or one of the following strings: "start", "mid" or "end".',
):
qim3d.viz.slices(example_volume, position=1.5)
qim3d.viz.slices_grid(example_volume, position=1.5)
def test_slices_wrong_position_format3():
......@@ -95,7 +95,7 @@ def test_slices_wrong_position_format3():
ValueError,
match='Position not recognized. Choose an integer, list of integers or one of the following strings: "start", "mid" or "end".',
):
qim3d.viz.slices(example_volume, position=[1, 2, 3.5])
qim3d.viz.slices_grid(example_volume, position=[1, 2, 3.5])
def test_slices_invalid_axis_value():
......@@ -104,14 +104,14 @@ def test_slices_invalid_axis_value():
ValueError,
match="Invalid value for 'axis'. It should be an integer between 0 and 2",
):
qim3d.viz.slices(example_volume, axis=3)
qim3d.viz.slices_grid(example_volume, axis=3)
def test_slices_interpolation_option():
example_volume = np.ones((10, 10, 10))
img_width = 3
interpolation_method = "bilinear"
fig = qim3d.viz.slices(
fig = qim3d.viz.slices_grid(
example_volume,
n_slices=1,
img_width=img_width,
......@@ -130,7 +130,7 @@ def test_slices_multiple_slices():
example_volume = np.ones((10, 10, 10))
img_width = 3
n_slices = 3
fig = qim3d.viz.slices(example_volume, n_slices=n_slices, img_width=img_width)
fig = qim3d.viz.slices_grid(example_volume, n_slices=n_slices, img_width=img_width)
# Add assertions for the expected number of subplots in the figure
assert len(fig.get_axes()) == n_slices
......@@ -141,13 +141,13 @@ def test_slices_axis_argument():
img_width = 3
# Call the function with different values of the axis
fig_axis_0 = qim3d.viz.slices(
fig_axis_0 = qim3d.viz.slices_grid(
example_volume, n_slices=1, img_width=img_width, axis=0
)
fig_axis_1 = qim3d.viz.slices(
fig_axis_1 = qim3d.viz.slices_grid(
example_volume, n_slices=1, img_width=img_width, axis=1
)
fig_axis_2 = qim3d.viz.slices(
fig_axis_2 = qim3d.viz.slices_grid(
example_volume, n_slices=1, img_width=img_width, axis=2
)
......
......@@ -30,7 +30,7 @@ def plot_cc(
cmap (str, optional): Specifies the color map for the image. Defaults to "viridis".
vmin (float, optional): Together with vmax define the data range the colormap covers. By default colormap covers the full range. Defaults to None.
vmax (float, optional): Together with vmin define the data range the colormap covers. By default colormap covers the full range. Defaults to None
**kwargs: Additional keyword arguments to pass to `qim3d.viz.slices`.
**kwargs: Additional keyword arguments to pass to `qim3d.viz.slices_grid`.
Returns:
figs (list[plt.Figure]): List of figures, if `show=False`.
......@@ -75,14 +75,14 @@ def plot_cc(
else:
cc = connected_components.get_cc(component, crop=False)
overlay_crop = np.where(cc == 0, 0, overlay)
fig = qim3d.viz.slices(overlay_crop, show=show, cmap = cmap, vmin = vmin, vmax = vmax, **kwargs)
fig = qim3d.viz.slices_grid(overlay_crop, show=show, cmap = cmap, vmin = vmin, vmax = vmax, **kwargs)
else:
# assigns discrete color map to each connected component if not given
if "cmap" not in kwargs:
kwargs["cmap"] = qim3d.viz.colormaps.objects(len(component_indexs))
# Plot the connected component without overlay
fig = qim3d.viz.slices(
fig = qim3d.viz.slices_grid(
connected_components.get_cc(component, crop=crop), show=show, **kwargs
)
......
......@@ -89,7 +89,7 @@ def objects(
Tip:
It can be easily used when calling visualization functions as
```python
qim3d.viz.slices(segmented_volume, cmap = 'objects')
qim3d.viz.slices_grid(segmented_volume, cmap = 'objects')
```
which automatically detects number of unique classes
and creates the colormap object with defualt arguments.
......
......@@ -77,7 +77,7 @@ def slices_grid(
import qim3d
vol = qim3d.examples.shell_225x128x128
qim3d.viz.slices_grid(vol, num_slices=15)
qim3d.viz.slices_grid_grid(vol, num_slices=15)
```
![Grid of slices](assets/screenshots/viz-slices.png)
"""
......@@ -690,7 +690,7 @@ def chunks(zarr_path: str, **kwargs):
viz_widget = widgets.Output()
with viz_widget:
viz_widget.clear_output(wait=True)
fig = qim3d.viz.slices_grid(chunk, **kwargs)
fig = qim3d.viz.slices_grid_grid(chunk, **kwargs)
display(fig)
elif visualization_method == "volume":
viz_widget = widgets.Output()
......
......@@ -29,7 +29,7 @@ def circles(blobs, vol, alpha=0.5, color="#ff9900", **kwargs):
def _slicer(z_slice):
clear_output(wait=True)
fig = qim3d.viz.slices(
fig = qim3d.viz.slices_grid(
vol,
n_slices=1,
position=z_slice,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment