diff --git a/docs/assets/screenshots/CLI-k3d.png b/docs/assets/screenshots/CLI-k3d.png index 41e8fc499041c463e3c0763aecff2c844a3f7f7c..88967ae209d2ca3b6f89629cdd18060c09620dff 100644 Binary files a/docs/assets/screenshots/CLI-k3d.png and b/docs/assets/screenshots/CLI-k3d.png differ diff --git a/docs/assets/screenshots/local_thickness_2d.png b/docs/assets/screenshots/local_thickness_2d.png index de3b9bc38c230efca50a6fd2d6743ffa583837af..3c8a64cd59b8e16b34f6314f7a51d4adab4a7fcd 100644 Binary files a/docs/assets/screenshots/local_thickness_2d.png and b/docs/assets/screenshots/local_thickness_2d.png differ diff --git a/docs/assets/screenshots/synthetic_blob_slices.png b/docs/assets/screenshots/synthetic_blob_slices.png index 549ae27ebf837cc108ecea7454849de480c4a44b..bbfeb3a59046a70c4083d36640ba0e04e9dead47 100644 Binary files a/docs/assets/screenshots/synthetic_blob_slices.png and b/docs/assets/screenshots/synthetic_blob_slices.png differ diff --git a/docs/cli.md b/docs/cli.md index 6295a98c2d38e575a45a8efc863d854c88375b43..a8d1d42e681b5b990b8d89060324c022115511ef 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -142,12 +142,20 @@ You can launch volumetric visualizations directly from the command line. By defa ``` ``` title="Output" - Loading data from blobs_256x256x256.tif - Done, volume shape: (256, 256, 256) + Loading data from cement_128x128x128.tif + Loading: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2.02MB/2.02MB [00:00<00:00, 936MB/s] + Volume using 2.0 MB of memory + + System memory: + • Total.: 31.0 GB + • Used..: 18.8 GB (60.8%) + • Free..: 12.1 GB (39.2%) + Done, volume shape: (128, 128, 128) Generating k3d plot... Done, plot available at <k3d.html> Opening in default browser... + ``` And a new tab will be opened in the default browser with the interactive k3d plot: @@ -155,17 +163,26 @@ You can launch volumetric visualizations directly from the command line. By defa Or an specific path for destination can be used. We can also choose to not open the browser: -!!! Example "Example using k3d, saving html to custom path" - ``` title="Command" - qim3d viz --source blobs_256x256x256.tif --destination my_plot.html --no-browser +!!! Example + ``` + qim3d viz cement_128x128x128.tif --destination my_plot.html --no-browser + ``` ``` title="Output" - Loading data from blobs_256x256x256.tif - Done, volume shape: (256, 256, 256) + Loading data from cement_128x128x128.tif + Loading: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2.02MB/2.02MB [00:00<00:00, 909MB/s] + Volume using 2.0 MB of memory + + System memory: + • Total.: 31.0 GB + • Used..: 18.9 GB (61.1%) + • Free..: 12.0 GB (38.9%) + Done, volume shape: (128, 128, 128) Generating k3d plot... Done, plot available at <my_plot.html> + ``` This writes to disk the `my_plot.html` file. diff --git a/qim3d/generate/blob_.py b/qim3d/generate/blob_.py index 58a030f47fed687b32de06f94796be98005b080c..ed7f6f6c25b4d8be64853bcba674d5d8b761c046 100644 --- a/qim3d/generate/blob_.py +++ b/qim3d/generate/blob_.py @@ -39,7 +39,7 @@ def blob( import qim3d # Generate synthetic blob - synthetic_blob = qim3d.generate.blob(noise_scale = 0.05) + synthetic_blob = qim3d.generate.blob(noise_scale = 0.015) # Visualize slices qim3d.viz.slices(synthetic_blob, vmin = 0, vmax = 255, n_slices = 15) diff --git a/qim3d/io/loading.py b/qim3d/io/loading.py index f00dc33b020420edab64d2124ce3ad1059924b17..ce3f8f1360fce70315ba11e35165f1a1dbba116a 100644 --- a/qim3d/io/loading.py +++ b/qim3d/io/loading.py @@ -51,10 +51,6 @@ class DataLoader: load_txrm(path): Load a TXRM/TXM/XRM file from the specified path load_vol(path): Load a VOL file from the specified path. Path should point to the .vgi metadata file load(path): Load a file or directory based on the given path - - Example: - loader = qim3d.io.DataLoader(virtual_stack=True) - data = loader.load_tiff("image.tif") """ def __init__(self, **kwargs): @@ -675,10 +671,6 @@ class DataLoader: ValueError: If the format is not supported ValueError: If the file or directory does not exist. MemoryError: If file size exceeds available memory and force_load is not set to True. In check_size function. - - Example: - loader = qim3d.io.DataLoader() - data = loader.load("image.tif") """ # Stringify path in case it is not already a string diff --git a/qim3d/io/saving.py b/qim3d/io/saving.py index a89206a2c1526a1bc3b88515f76908a81cf67cc2..4ba7ef00dfe12fe7bbec2e44e6731529b87db75c 100644 --- a/qim3d/io/saving.py +++ b/qim3d/io/saving.py @@ -6,18 +6,20 @@ Example: ```python import qim3d - vol = qim3d.examples.fly_150x256x256 + # Generate synthetic blob + synthetic_blob = qim3d.generate.blob(noise_scale = 0.015) - qim3d.io.save("fly.tif", vol) + qim3d.io.save("fly.tif", synthetic_blob) ``` Volumes can also be saved with one file per slice: ```python import qim3d - vol = qim3d.examples.fly_150x256x256 + # Generate synthetic blob + synthetic_blob = qim3d.generate.blob(noise_scale = 0.015) - qim3d.io.save("slices", vol, basename="fly-slices", sliced_dim=0) + qim3d.io.save("slices", synthetic_blob, basename="fly-slices", sliced_dim=0) ``` """ @@ -53,11 +55,6 @@ class DataSaver: Methods: save_tiff(path,data): Save data to a TIFF file to the given path. load(path,data): Save data to the given path. - - Example: - image = qim3d.examples.blobs_256x256 - saver = qim3d.io.DataSaver(compression=True) - saver.save_tiff("image.tif",image) """ def __init__(self, **kwargs): @@ -319,12 +316,6 @@ class DataSaver: ValueError: If the provided path does not exist and self.basename is not provided ValueError: If a file extension is not provided. ValueError: if a file with the specified path already exists and replace=False. - - Example: - image = qim3d.examples.blobs_256x256 - saver = qim3d.io.DataSaver(compression=True) - saver.save("image.tif",image) - """ path = stringify_path(path) @@ -438,8 +429,20 @@ def save( ```python import qim3d - vol = qim3d.examples.blobs_256x256x256 - qim3d.io.save("blobs.tif", vol) + # Generate synthetic blob + synthetic_blob = qim3d.generate.blob(noise_scale = 0.015) + + qim3d.io.save("blob.tif", synthetic_blob, replace=True) + ``` + + Volumes can also be saved with one file per slice: + ```python + import qim3d + + # Generate synthetic blob + synthetic_blob = qim3d.generate.blob(noise_scale = 0.015) + + qim3d.io.save("slices", synthetic_blob, basename="blob-slices", sliced_dim=0) ``` """ diff --git a/qim3d/models/unet.py b/qim3d/models/unet.py index 3d25a78af9f2ecc5305807228c39d790e06c6960..6c57f55e44eb13403a39d36b8a85c5d400cc00ea 100644 --- a/qim3d/models/unet.py +++ b/qim3d/models/unet.py @@ -22,11 +22,6 @@ class UNet(nn.Module): Raises: ValueError: If `size` is not one of 'small', 'medium', or 'large'. - - Example: - ```python - model = UNet(size='large') - ``` """ def __init__( @@ -104,13 +99,21 @@ class Hyperparameters: Example: ``` - hyperparams = Hyperparameters(model=my_model, n_epochs=20, learning_rate=0.001) + import qim3d - params_dict = hyperparams() # Get the hyperparameters + # This examples shows how to define a UNet model and its hyperparameters. + # Defining the model + my_model = qim3d.models.UNet(size='medium') + + # Choosing the hyperparameters + hyperparams = qim3d.models.Hyperparameters(model=my_model, n_epochs=20, learning_rate=0.001) + + params_dict = hyperparams() # Get the hyperparameters optimizer = params_dict['optimizer'] criterion = params_dict['criterion'] n_epochs = params_dict['n_epochs'] + ``` """ diff --git a/qim3d/processing/local_thickness_.py b/qim3d/processing/local_thickness_.py index 96968519c0f9723db9828ea9798b2f00e9834d30..f106cbcbb6de1f14e47d256fd654106a9e5ff5ac 100644 --- a/qim3d/processing/local_thickness_.py +++ b/qim3d/processing/local_thickness_.py @@ -48,8 +48,14 @@ def local_thickness( ```python import qim3d - blobs = qim3d.examples.blobs_256x256 # 2D image - lt_blobs = qim3d.processing.local_thickness(blobs, visualize=True) + # Generate synthetic collection of blobs + num_objects = 15 + synthetic_collection, labels = qim3d.generate.collection(num_objects = num_objects) + + # Extract one slice to show that localthickness works on 2D slices too + slice = synthetic_collection[:,:,50] + lt_blobs = qim3d.processing.local_thickness(slice, visualize=True) + ```  diff --git a/qim3d/processing/mesh.py b/qim3d/processing/mesh.py index e0ea24336bb37e98b1b1050d79db58b6033e8f69..88ff3de80351e3a345983b55c6e920b713967d3d 100644 --- a/qim3d/processing/mesh.py +++ b/qim3d/processing/mesh.py @@ -2,6 +2,7 @@ import numpy as np from skimage import measure, filters import trimesh from typing import Tuple, Any +from qim3d.utils.logger import log def create_mesh( @@ -35,7 +36,7 @@ def create_mesh( threshold=0.5, dtype='uint8' ) - mesh = qim3d.processing.create_mesh(vol step_size=3) + mesh = qim3d.processing.create_mesh(vol, step_size=3) qim3d.viz.mesh(mesh.vertices, mesh.faces) ``` @@ -46,7 +47,7 @@ def create_mesh( # Compute the threshold level if not provided if level is None: level = filters.threshold_otsu(volume) - print(f"Computed level using Otsu's method: {level}") + log.info(f"Computed level using Otsu's method: {level}") # Apply padding to the volume if padding is not None: @@ -58,15 +59,13 @@ def create_mesh( mode="constant", constant_values=padding_value, ) - print(f"Padded volume with {padding} to shape: {volume.shape}") + log.info(f"Padded volume with {padding} to shape: {volume.shape}") # Call skimage.measure.marching_cubes with user-provided kwargs verts, faces, normals, values = measure.marching_cubes( volume, level=level, step_size=step_size, **kwargs ) - print(len(verts)) - # Create the Trimesh object mesh = trimesh.Trimesh(vertices=verts, faces=faces) diff --git a/qim3d/processing/operations.py b/qim3d/processing/operations.py index 946605e89486b1e808900e2f917ac49accb273a2..982c6960378ea49b987a655a9840937621171f63 100644 --- a/qim3d/processing/operations.py +++ b/qim3d/processing/operations.py @@ -73,7 +73,7 @@ def watershed(bin_vol: np.ndarray, min_distance: int = 5) -> tuple[np.ndarray, i import qim3d vol = qim3d.examples.cement_128x128x128 - binary = qim3d.processing.filters.gaussian(vol, 2)<60 + binary = qim3d.processing.filters.gaussian(vol, sigma = 2)<60 qim3d.viz.slices(binary, axis=1) ``` @@ -83,7 +83,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(labeled_volume, axis = 1, cmap = cmap) ```  diff --git a/qim3d/viz/colormaps.py b/qim3d/viz/colormaps.py index e99b0fd81c5e6371cdd43464c029049a98df99aa..ac9fb66c3721120e1738efb3cd5eb45d57ac827e 100644 --- a/qim3d/viz/colormaps.py +++ b/qim3d/viz/colormaps.py @@ -78,7 +78,7 @@ def objects( import qim3d vol = qim3d.examples.cement_128x128x128 - binary = qim3d.processing.filters.gaussian(vol, 2) < 60 + binary = qim3d.processing.filters.gaussian(vol, sigma = 2) < 60 labeled_volume, num_labels = qim3d.processing.operations.watershed(binary) cmap = qim3d.viz.colormaps.objects(num_labels, style = 'bright') diff --git a/qim3d/viz/explore.py b/qim3d/viz/explore.py index 8dfa322eb72b1da84cd750d976137f7287aa5db3..54a4b03449dbb3e0c95d5238ae5fff9e0947d5ff 100644 --- a/qim3d/viz/explore.py +++ b/qim3d/viz/explore.py @@ -411,7 +411,7 @@ def interactive_fade_mask(vol: np.ndarray, axis: int = 0,cmap:str = 'viridis', v return fig shape_dropdown = widgets.Dropdown( - options=["spherical", "cylindrical"], + options=["spherical", "cylindrical"], value="spherical", # default value description="Geometry", )