From 59e93cf736936dc88271fc8a92c82ca8e6b4bd5a Mon Sep 17 00:00:00 2001 From: <> Date: Fri, 21 Jun 2024 13:15:35 +0000 Subject: [PATCH] Deployed ffe82e2 with MkDocs version: 1.6.0 --- faq/index.html | 20 ++++++++++++++ index.html | 55 +++++++++++++++++++++++++++++++++++---- search/search_index.json | 2 +- sitemap.xml | 16 ++++++------ sitemap.xml.gz | Bin 279 -> 279 bytes 5 files changed, 79 insertions(+), 14 deletions(-) diff --git a/faq/index.html b/faq/index.html index fa3926c..2f4e26f 100644 --- a/faq/index.html +++ b/faq/index.html @@ -496,6 +496,15 @@ + + +
Make sure to run %matplotlib widget alongwith other library
models.track_fibres either requires detected coordinates coords or normalized volume vol. It is suggested to use both if calculated coords available during smoothening to avoid re-compute.
+Yes, this library works locally and does not need very high computing power to use it. Load depends on memory size of data which you are going to use.
FAQ will be updated based on user experiences
diff --git a/index.html b/index.html
index 80cd11d..17a47bc 100644
--- a/index.html
+++ b/index.html
@@ -640,20 +640,65 @@ FibreTracker
A python library to track fibre in a volume
Create a new environment (highly recommended)
-conda create -n fibretracker python=3.11
+
+Miniconda installation and setup
+Miniconda is a free lightweight installer for conda.
+Here are commands to quickly setup the conda. For reference, you can also use installation link
+
+
+
+Following commands will install the latest 64-bit version and delete the installer. To install different version change the .exe
version to desired version in the curl
command line.
+
+After successful installation, search and open "Ananconda prompt (miniconda3)".
+
+
+Following commands will install the latest 64-bit version and delete the installer. To install different version change the .sh
version to desired version in the curl
command line.
+mkdir -p ~/miniconda3
+curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o ~/miniconda3/miniconda.sh
+bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
+rm -rf ~/miniconda3/miniconda.sh
+
+After successful installation, initialize your miniconda (in general, it is intialized; just close the current terminal and open a new terminal). If not, following commands initialize for bash and zsh shells :
+
+
+
+Following commands will install the latest 64-bit version and delete the installer. To install different version change the .sh
version to desired version in the wget
command line.
+mkdir -p ~/miniconda3
+wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
+bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
+rm -rf ~/miniconda3/miniconda.sh
+
+After installing, initialize your newly-installed Miniconda (in general, it is initialized; just close the current terminal and open a new terminal). If not, following commands initialize for bash and zsh shells:
+
+
+
+
+
+Once installed, create the environment
+
Activate the environment by running
-conda activate fibretracker
+
To read .txm file, install dxchange
using conda
[install before fibretracker module to avoid version conflicts and related error]
-conda install -c conda-forge dxchange
+
Install the FibreTracker tool using pip
-pip install fibretracker
+
+Open jupyter notebook and create a new notebook
+
Go to Example and run the notebook with fibretracker
enviroment
Data
-Following are the dataset on which fibre tracking is tested on 250 slices
+Following are the dataset for which fibre tracking is tested on 250 slices
- Mock and UD [link] -
UD-01_FoV_2_B2_recon.txm
Mock-01_FoV_2_B2_recon.txm
diff --git a/search/search_index.json b/search/search_index.json
index 5026e71..25a9e34 100644
--- a/search/search_index.json
+++ b/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"FibreTracker","text":"A python library to track fibre in a volume
"},{"location":"#getting-started","title":"\ud83d\udcbb Getting Started","text":"Create a new environment (highly recommended)
conda create -n fibretracker python=3.11\n
Activate the environment by running
conda activate fibretracker\n
To read .txm file, install dxchange
using conda
[install before fibretracker module to avoid version conflicts and related error]
conda install -c conda-forge dxchange\n
Install the FibreTracker tool using pip
pip install fibretracker\n
Go to Example and run the notebook with fibretracker
enviroment
"},{"location":"#data","title":"Data","text":"Following are the dataset on which fibre tracking is tested on 250 slices
- Mock and UD [link] -
UD-01_FoV_2_B2_recon.txm
Mock-01_FoV_2_B2_recon.txm
- GFRP [link] -
GFRP_Initial.zip
- XCT Low-Res [link] -
XCT_L.zip
"},{"location":"#license","title":"License","text":"fibretracker
was created by Kumari Pooja. It is licensed under the terms of the MIT license.
"},{"location":"#credits","title":"Credits","text":"This work is supported by the RELIANCE doctoral network via the Marie Sk\u0142odowska-Curie Actions HORIZON-MSCA-2021-DN- 01. Project no: 101073040
Project based on the cookiecutter data science project template. #cookiecutterdatascience
"},{"location":"CHANGELOG/","title":"Versions History","text":""},{"location":"CHANGELOG/#v010-20062024","title":"v0.1.0 (20/06/2024)","text":" - First release of
fibretracker
!
"},{"location":"detector/","title":"Documention for fibre detection","text":"To detect fibre centre in a slice
"},{"location":"detector/#fibretracker.models","title":"fibretracker.models","text":""},{"location":"detector/#fibretracker.models.get_fibre_coords","title":"fibretracker.models.get_fibre_coords","text":"get_fibre_coords(vol, std=2.5, min_distance=3, threshold_abs=0.4, weighted_avg=False, window_size=10, apply_filter=False)\n
Get list of fibres centre coordinates in a volume using blob detector
Parameters:
Name Type Description Default vol
ndarray
input volume
required std
float
standard deviation of the Gaussian filter
2.5
min_distance
int
minimum distance between fibres
3
threshold_abs
float
threshold value for the peak from the background
0.4
weighted_avg
bool
whether to apply weighted average to the detected coordinates
False
window_size
int
size of the neighbourhood window around the peak
10
apply_filter
bool
whether to apply Gaussian filter to the window
False
Returns:
Name Type Description coords
List(array)
List of fibres centre coordinates in the volume
Example import fibretracker as ft\n\nvol = ft.detector.get_fib_coords(vol, std=2.5, min_distance=3, threshold_abs=0.4)\n
Source code in fibretracker/models/detector.py
def get_fibre_coords(\n vol: np.ndarray, \n std: float=2.5, \n min_distance: int=3, \n threshold_abs: float=0.4,\n weighted_avg: bool=False,\n window_size: int=10,\n apply_filter: bool=False,\n ):\n ''' Get list of fibres centre coordinates in a volume using blob detector\n\n Args:\n vol: input volume\n std: standard deviation of the Gaussian filter\n min_distance: minimum distance between fibres\n threshold_abs: threshold value for the peak from the background\n weighted_avg: whether to apply weighted average to the detected coordinates\n window_size: size of the neighbourhood window around the peak\n apply_filter: whether to apply Gaussian filter to the window\n\n Returns:\n coords (List(nd.array)): List of fibres centre coordinates in the volume\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.detector.get_fib_coords(vol, std=2.5, min_distance=3, threshold_abs=0.4)\n ```\n\n '''\n coords = []\n for i, im in enumerate(vol):\n coord = blob_centre_detector(im, std=std, min_distance=min_distance, threshold_abs=threshold_abs)\n if weighted_avg:\n coord = avg_fibre_coord(coord, im, window_size=window_size, apply_filter=apply_filter, std=std)\n coords.append(np.stack([coord[:,1], coord[:,0], np.ones(len(coord)) * i], axis=1))\n print(f'Detecting coordinates - slice: {i+1}/{len(vol)}', end='\\r')\n print(' ' * len(f'Detecting coordinates - slice: {i+1}/{len(vol)}'), end='\\r')\n return coords\n
"},{"location":"detector/#fibretracker.models.blob_centre_detector","title":"fibretracker.models.blob_centre_detector","text":"blob_centre_detector(im, std=2.5, min_distance=3, threshold_abs=0.4)\n
Predict coordinates of fibres centre in a volume slice using blob detector
Parameters:
Name Type Description Default im
ndarray
input image
required std
float
standard deviation of the Gaussian filter
2.5
min_distance
int
minimum distance between peaks
3
threshold_abs
float
threshold value for the peak from the background
0.4
Returns:
Name Type Description pred_coords
ndarray
predicted coordinates of the fibre centre
Example import fibretracker as ft\n\nvol = ft.detector.blob_centre_detector(im, std=2.5, min_distance=3, threshold_abs=0.4)\n
Source code in fibretracker/models/detector.py
def blob_centre_detector(\n im: np.ndarray, \n std: float=2.5, \n min_distance: int=3, \n threshold_abs: float=0.4\n ):\n ''' Predict coordinates of fibres centre in a volume slice using blob detector\n\n Args: \n im: input image\n std: standard deviation of the Gaussian filter\n min_distance: minimum distance between peaks\n threshold_abs: threshold value for the peak from the background\n\n Returns: \n pred_coords (np.ndarray): predicted coordinates of the fibre centre\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.detector.blob_centre_detector(im, std=2.5, min_distance=3, threshold_abs=0.4)\n ```\n\n '''\n g = gauss_filter(std)[0]\n im_g = scipy.ndimage.convolve(scipy.ndimage.convolve(im, g), g.T)\n pred_coords = skimage.feature.peak_local_max(im_g, min_distance=min_distance, threshold_abs=threshold_abs)\n return pred_coords\n
"},{"location":"detector/#fibretracker.models.gauss_filter","title":"fibretracker.models.gauss_filter","text":"gauss_filter(std)\n
Generate a 1D Gaussian filter and its derivatives
Parameters:
Name Type Description Default std
float
standard deviation of the Gaussian filter
required Returns:
Name Type Description g
ndarray
1D Gaussian filter
dg
ndarray
derivative of the Gaussian filter
ddg
ndarray
second derivative of the Gaussian filter
Example import fibretracker as ft\n\nvol = ft.detector.gauss_filter(std=2.5)\n
Source code in fibretracker/models/detector.py
def gauss_filter(\n std: float\n ):\n ''' Generate a 1D Gaussian filter and its derivatives\n\n Args: \n std: standard deviation of the Gaussian filter\n\n Returns:\n g (np.ndarray): 1D Gaussian filter\n dg (np.ndarray): derivative of the Gaussian filter\n ddg (np.ndarray): second derivative of the Gaussian filter\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.detector.gauss_filter(std=2.5)\n ```\n\n '''\n x = np.arange(-np.ceil(5*std), np.ceil(5*std) + 1)[:,None]\n g = np.exp(-x**2/(2*std**2))\n g /= np.sum(g)\n dg = -x/std**2 * g\n ddg = -g/std**2 -x/std**2 * dg\n return g, dg, ddg\n
"},{"location":"detector/#fibretracker.models.avg_fibre_coord","title":"fibretracker.models.avg_fibre_coord","text":"avg_fibre_coord(pred_coord, im, window_size=10, apply_filter=False, std=None)\n
Recompute the fibre centre in a slice using weighted average of peak neighbourhood
Parameters:
Name Type Description Default pred_coord
ndarray
predicted coordinates of the peaks
required im
ndarray
input image
required window_size
int
size of the neighbourhood window around the peak
10
apply_filter
bool
whether to apply Gaussian filter to the window
False
std
Optional[float]
standard deviation of the Gaussian filter
None
Returns:
Name Type Description coords
ndarray
recomputed fibre centre coordinates in the slice with weighted average
Example import fibretracker as ft\n\navg_coord = ft.detector.avg_fib_coord(pred_coord, im, window_size)\n
Source code in fibretracker/models/detector.py
def avg_fibre_coord(\n pred_coord: np.ndarray, \n im: np.ndarray, \n window_size: int = 10,\n apply_filter: bool = False,\n std: Optional[float] = None\n ):\n ''' Recompute the fibre centre in a slice using weighted average of peak neighbourhood\n\n Args: \n pred_coord: predicted coordinates of the peaks\n im: input image\n window_size: size of the neighbourhood window around the peak\n apply_filter: whether to apply Gaussian filter to the window\n std: standard deviation of the Gaussian filter\n\n Returns:\n coords (np.ndarray): recomputed fibre centre coordinates in the slice with weighted average\n\n Example:\n ```python\n import fibretracker as ft\n\n avg_coord = ft.detector.avg_fib_coord(pred_coord, im, window_size)\n ```\n\n '''\n coords = []\n for coord in pred_coord:\n x, y = coord\n window = im[x-window_size//2:x+window_size//2+1, y-window_size//2:y+window_size//2+1]\n # Apply Gaussian filter to the window\n if apply_filter:\n if std is not None:\n g = gauss_filter(std)[0]\n else:\n g = gauss_filter(std=2.5)[0]\n window = scipy.ndimage.convolve(scipy.ndimage.convolve(window, g), g.T)\n x_coords, y_coords = np.meshgrid(range(x-window_size//2, x+window_size//2+1), range(y-window_size//2, y+window_size//2+1))\n weighted_x = np.sum(window * x_coords) / np.sum(window)\n weighted_y = np.sum(window * y_coords) / np.sum(window)\n coords.append([weighted_x, weighted_y])\n return np.array(coords)\n
"},{"location":"faq/","title":"Frequently Asked Questions","text":""},{"location":"faq/#vizorthogonal-and-vizslicer-are-not-showing-output","title":"viz.orthogonal and viz.slicer are not showing output","text":"Make sure to run %matplotlib widget alongwith other library
"},{"location":"faq/#how-modelstrack_fibres-works","title":"How models.track_fibres works ?","text":"models.track_fibres either requires detected coordinates coords or normalized volume vol. It is suggested to use both if calculated coords available during smoothening to avoid re-compute.
FAQ will be updated based on user experiences"},{"location":"io/","title":"Data input and output","text":"
Dealing with volumetric data can be done by fibretracker
for the most common image formats available.
Currently, it is possible to directly load tiff
, h5
, nii
,txm
and common PIL
formats using one single function.
"},{"location":"io/#fibretracker.io","title":"fibretracker.io","text":""},{"location":"io/#fibretracker.io.load","title":"fibretracker.io.load","text":"load(path, dataset_name=None, return_metadata=False, contains=None, force_load=False, dim_order=(2, 1, 0), **kwargs)\n
Load data from the specified file or directory.
Parameters:
Name Type Description Default path
str or PathLike
The path to the file or directory.
required dataset_name
str
Specifies the name of the dataset to be loaded in case multiple dataset exist within the same file. Default is None (only for HDF5 files)
None
return_metadata
bool
Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)
False
contains
str
Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks). Default is None.
None
force_load
bool
If the file size exceeds available memory, a MemoryError is raised. If force_load is True, the error is changed to warning and the loader tries to load it anyway. Default is False.
False
dim_order
tuple
The order of the dimensions in the volume for .vol files. Default is (2,1,0) which corresponds to (z,y,x)
(2, 1, 0)
**kwargs
Additional keyword arguments to be passed
{}
Returns:
Name Type Description vol
ndarray
The loaded volume If return_metadata=True
and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns tuple
(volume, metadata).
Raises:
Type Description MemoryError
if the given file size exceeds available memory
Example # Load volume from a single file\nimport fibretracker as ft\n\nvol = ft.io.load(data_path)\n
# Load a stack of TIFF files as a volume\nimport fibretracker as ft\n\nvol = ft.io.load(data_path, contains='.tif')\n
Source code in fibretracker/io/read_file.py
def load(\n path,\n dataset_name=None,\n return_metadata=False,\n contains=None,\n force_load: bool = False,\n dim_order=(2, 1, 0),\n **kwargs,\n):\n \"\"\"\n Load data from the specified file or directory.\n\n Args:\n path (str or os.PathLike): The path to the file or directory.\n dataset_name (str, optional): Specifies the name of the dataset to be loaded\n in case multiple dataset exist within the same file. Default is None (only for HDF5 files)\n return_metadata (bool, optional): Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)\n contains (str, optional): Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks).\n Default is None.\n force_load (bool, optional): If the file size exceeds available memory, a MemoryError is raised.\n If force_load is True, the error is changed to warning and the loader tries to load it anyway. Default is False.\n dim_order (tuple, optional): The order of the dimensions in the volume for .vol files. Default is (2,1,0) which corresponds to (z,y,x)\n **kwargs: Additional keyword arguments to be passed\n to the DataLoader constructor.\n\n Returns:\n vol (numpy.ndarray): The loaded volume\n If `return_metadata=True` and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns `tuple` (volume, metadata).\n\n Raises:\n MemoryError: if the given file size exceeds available memory\n\n Example:\n ```python\n # Load volume from a single file\n import fibretracker as ft\n\n vol = ft.io.load(data_path)\n ```\n ```python\n # Load a stack of TIFF files as a volume\n import fibretracker as ft\n\n vol = ft.io.load(data_path, contains='.tif')\n ```\n\n \"\"\"\n\n loader = DataLoader(\n dataset_name=dataset_name,\n return_metadata=return_metadata,\n contains=contains,\n force_load=force_load,\n dim_order=dim_order,\n **kwargs,\n )\n\n data = loader.load(path)\n\n return data\n
"},{"location":"io/#fibretracker.io.normalize","title":"fibretracker.io.normalize","text":"normalize(vol)\n
Normalize the volume to the range [0, 1] using min-max scaling.
Parameters:
Name Type Description Default vol
ndarray
The volume to normalize.
required Returns:
Name Type Description norm_vol
ndarray
The normalized volume.
Example import fibretracker as ft\n\nnorm_vol = ft.io.normalize(vol)\n
Source code in fibretracker/io/read_file.py
def normalize(\n vol: np.ndarray\n ):\n \"\"\"Normalize the volume to the range [0, 1] using min-max scaling.\n\n Args:\n vol (numpy.ndarray): The volume to normalize.\n\n Returns:\n norm_vol (numpy.ndarray): The normalized volume.\n\n Example:\n ```python\n import fibretracker as ft\n\n norm_vol = ft.io.normalize(vol)\n ```\n \"\"\"\n norm_vol = (vol - np.min(vol)) / (np.max(vol) - np.min(vol))\n return norm_vol\n
"},{"location":"tracker/","title":"For tracking file","text":"To detect fibre centre in a slice
"},{"location":"tracker/#fibretracker.models","title":"fibretracker.models","text":""},{"location":"tracker/#fibretracker.models.track_fibres","title":"fibretracker.models.track_fibres","text":"track_fibres(vol=None, max_jump=5, max_skip=5, momentum=0.1, track_min_length=5, coords=None, std=2.5, min_distance=5, threshold_abs=0.5, weighted_avg=False, window_size=10, apply_filter=False, smoothtrack_gaussian=False, sigma=3, smoothtrack_watershed=False, threshold=None)\n
Tracks fibers throughout the volume
Parameters:
Name Type Description Default vol
ndarray
3D volume.
None
max_jump
int
Maximum distance between detected points in two consecutive frames. Threshold in pixels.
5
max_skip
int
Maximum number of frames along one track where no points are detected.
5
momentum
float
Parameter in the range [0;1] that gives momentum to the tracking direction.
0.1
track_min_length
int
Minimum number of points in a track.
5
coords
list
List of numpy arrays with row and column indices of detected points. One per slice, which means that z is gives as the index of the list.
None
std
float
Standard deviation of the Gaussian filter.
2.5
min_distance
int
Minimum distance between fibres.
5
threshold_abs
float
Threshold value for the peak from the background.
0.5
weighted_avg
bool
Whether to apply weighted average to the detected coordinates.
False
window_size
int
Size of the neighbourhood window around the peak.
10
apply_filter
bool
Whether to apply Gaussian filter to the window.
False
smoothtrack_gaussian
bool
Whether to smooth tracks using Gaussian.
False
sigma
float
Sigma value for Gaussian filter.
3
smoothtrack_watershed
bool
Whether to smooth tracks using watershed.
False
threshold
float
Threshold value for watershed.
None
Returns:
Name Type Description tracks
List[ndarray]
List of arrays of shape (n_points, 3) - each list contains coordinates of tracked fibers.
Example import fibretracker as ft\n\nvol = ft.io.load(\"path/to/volume.txm\")\nv = ft.io.normalize(vol)\ncoords = ft.models.get_fibre_coords(v)\ntracks = ft.models.track_fibres(coords=coords)\n
import fibretracker as ft\n\nvol = ft.io.load(\"path/to/volume.txm\")\nv = ft.io.normalize(vol)\ncoords = ft.models.get_fibre_coords(v)\ntracks = ft.models.track_fibres(vol=v, coords=coords, smoothtrack_gaussian=True, sigma=3) # Smoothened tracks using Gaussian\n
Source code in fibretracker/models/tracker.py
def track_fibres(\n vol: Optional[np.ndarray]=None,\n max_jump: int=5, \n max_skip: int=5, \n momentum: float=0.1, \n track_min_length: int=5,\n coords: Optional[List[np.ndarray]]=None,\n std: float=2.5,\n min_distance: int=5,\n threshold_abs: float=0.5,\n weighted_avg: bool=False,\n window_size: int=10,\n apply_filter: bool=False,\n smoothtrack_gaussian: bool=False,\n sigma: float=3,\n smoothtrack_watershed: bool=False,\n threshold: Optional[float]=None\n ):\n '''Tracks fibers throughout the volume\n\n Args:\n vol (np.ndarray, optional): 3D volume.\n max_jump (int, optional): Maximum distance between detected points in two consecutive frames. Threshold in pixels.\n max_skip (int, optional): Maximum number of frames along one track where no points are detected.\n momentum (float, optional): Parameter in the range [0;1] that gives momentum to the tracking direction.\n track_min_length (int, optional): Minimum number of points in a track.\n coords (list, optional): List of numpy arrays with row and column indices of detected points. One per slice, which\n means that z is gives as the index of the list.\n std (float, optional): Standard deviation of the Gaussian filter.\n min_distance (int, optional): Minimum distance between fibres.\n threshold_abs (float, optional): Threshold value for the peak from the background.\n weighted_avg (bool, optional): Whether to apply weighted average to the detected coordinates.\n window_size (int, optional): Size of the neighbourhood window around the peak.\n apply_filter (bool, optional): Whether to apply Gaussian filter to the window.\n smoothtrack_gaussian (bool, optional): Whether to smooth tracks using Gaussian.\n sigma (float, optional): Sigma value for Gaussian filter.\n smoothtrack_watershed (bool, optional): Whether to smooth tracks using watershed.\n threshold (float, optional): Threshold value for watershed.\n\n Returns:\n tracks (List[np.ndarray]): List of arrays of shape (n_points, 3) - each list contains coordinates of tracked fibers.\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.io.load(\"path/to/volume.txm\")\n v = ft.io.normalize(vol)\n coords = ft.models.get_fibre_coords(v)\n tracks = ft.models.track_fibres(coords=coords)\n ```\n ```python\n import fibretracker as ft\n\n vol = ft.io.load(\"path/to/volume.txm\")\n v = ft.io.normalize(vol)\n coords = ft.models.get_fibre_coords(v)\n tracks = ft.models.track_fibres(vol=v, coords=coords, smoothtrack_gaussian=True, sigma=3) # Smoothened tracks using Gaussian\n ```\n\n\n '''\n\n fib_tracker = TrackPoints(max_jump=max_jump, max_skip=max_skip,\n momentum=momentum, track_min_length=track_min_length)\n\n if coords is None:\n coords = get_fibre_coords(vol, std=std, min_distance=min_distance, threshold_abs=threshold_abs, \n weighted_avg=weighted_avg, window_size=window_size, apply_filter=apply_filter)\n\n tracks, _ = fib_tracker(coords)\n if smoothtrack_gaussian:\n print('Smoothing tracks using Gaussian')\n tracks_smooth = []\n for track in tracks:\n tracks_smooth.append(gaussian_filter1d(track, sigma=sigma, axis=0))\n\n return tracks_smooth\n\n elif smoothtrack_watershed and vol is not None:\n print('Smoothing tracks using watershed...')\n tracks_filled = fib_tracker.fill_tracks(tracks)\n if threshold is None:\n threshold = threshold_otsu(vol[len(vol)//2])\n V_thres = vol > threshold\n V_dist = -distance_transform_edt(V_thres)\n V_coords = np.zeros(vol.shape)\n for i, track in enumerate(tracks_filled):\n for point in track:\n V_coords[int(point[2]), int(point[1]), int(point[0])] = i + 1\n V_ws = watershed(V_dist, markers=V_coords.astype(int))*V_thres\n print('Watershed volume created.')\n n_fibers = V_ws.max()\n tracks_smooth = [[] for i in range(n_fibers)]\n\n for i, v_ws in enumerate(V_ws):\n props = regionprops(v_ws)\n for prop in props:\n tracks_smooth[prop.label-1].append(list(prop.centroid[::-1]) + [i])\n print(f'Smoothing tracks - iteration: {i+1}/{len(V_ws)}', end='\\r')\n\n for i in range(n_fibers):\n tracks_smooth[i] = np.array(tracks_smooth[i])\n\n return tracks_smooth\n\n else:\n return tracks\n
"},{"location":"viz/","title":"Visualise detected centre and tracked fibre","text":"To visualise volume accross the slice, detected centres and tracked fibre
"},{"location":"viz/#fibretracker.viz","title":"fibretracker.viz","text":""},{"location":"viz/#fibretracker.viz.orthogonal","title":"fibretracker.viz.orthogonal","text":"orthogonal(vol, cmap='gray', img_height=5, img_width=5)\n
Interactive widget for visualizing orthogonal slices of a 3D volume.
Parameters:
Name Type Description Default vol
ndarray or Tensor
The 3D volume to be sliced.
required cmap
str
Specifies the color map for the image. Defaults to \"gray\".
'gray'
img_height(int,
optional
Height of the figure.
required img_width(int,
optional
Width of the figure.
required Returns:
Name Type Description orthogonal_obj
HBox
The interactive widget for visualizing orthogonal slices of a 3D volume.
Example import fibretracker as ft\n\nvol = ft.io.load(\"path/to/volume.txm\")\nft.viz.orthogonal(vol, cmap=\"gray\")\n
Source code in fibretracker/viz/visualize.py
def orthogonal(\n vol: np.ndarray,\n cmap: str = \"gray\",\n img_height: int = 5,\n img_width: int = 5\n)-> widgets.HBox:\n \"\"\"Interactive widget for visualizing orthogonal slices of a 3D volume.\n\n Args:\n vol (np.ndarray or torch.Tensor): The 3D volume to be sliced.\n cmap (str, optional): Specifies the color map for the image. Defaults to \"gray\".\n img_height(int, optional): Height of the figure.\n img_width(int, optional): Width of the figure.\n\n Returns:\n orthogonal_obj (widgets.HBox): The interactive widget for visualizing orthogonal slices of a 3D volume.\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.io.load(\"path/to/volume.txm\")\n ft.viz.orthogonal(vol, cmap=\"gray\")\n ```\n \n \"\"\"\n\n fig, ax = plt.subplots(1, 3, figsize=(3*img_width, img_height))\n ax[0].axis(\"off\")\n ax[1].axis(\"off\")\n ax[2].axis(\"off\")\n\n def _slice(slice_idx_z, slice_idx_y, slice_idx_x):\n slice_img_z = vol.take(slice_idx_z, axis=0)\n slice_img_y = vol.take(slice_idx_y, axis=1)\n slice_img_x = vol.take(slice_idx_x, axis=2)\n\n ax[0].imshow(slice_img_z, cmap=cmap)\n ax[0].set_aspect('equal')\n ax[1].imshow(slice_img_y, cmap=cmap)\n ax[1].set_aspect('equal')\n ax[2].imshow(slice_img_x, cmap=cmap)\n ax[2].set_aspect('equal')\n\n slice_slider_z = widgets.IntSlider(\n value=vol.shape[0] // 2,\n min=0,\n max=vol.shape[0] - 1,\n description=\"Z\",\n continuous_update=True,\n )\n\n slice_slider_y = widgets.IntSlider(\n value=vol.shape[1] // 2,\n min=0,\n max=vol.shape[1] - 1,\n description=\"Y\",\n continuous_update=True,\n )\n\n slice_slider_x = widgets.IntSlider(\n value=vol.shape[2] // 2,\n min=0,\n max=vol.shape[2] - 1,\n description=\"X\",\n continuous_update=True,\n )\n\n slicer_obj = interactive(_slice, slice_idx_z=slice_slider_z, slice_idx_y=slice_slider_y, slice_idx_x=slice_slider_x)\n\n # Create a horizontal box for the sliders\n hbox = widgets.HBox([slicer_obj.children[0], slicer_obj.children[1], slicer_obj.children[2]], layout=widgets.Layout(align_items=\"stretch\", justify_content=\"center\", align_content=\"center\", justify_items=\"center\", justify_self=\"center\", align_self=\"center\", width=\"100%\"))\n\n # Replace the sliders in the interactive widget with the horizontal box\n slicer_obj.children = (hbox,) + slicer_obj.children[3:]\n\n return slicer_obj\n
"},{"location":"viz/#fibretracker.viz.slicer","title":"fibretracker.viz.slicer","text":"slicer(vol, detect_coords=None, mark_size=None, axis=0, cmap='gray', img_height=5, img_width=5)\n
Interactive widget for visualizing slices of a 3D volume and fibres centre if provided.
Parameters:
Name Type Description Default vol
ndarray
The 3D volume to be sliced.
required detect_coords
list
List of coordinates of detected fibres. Defaults to None.
None
mark_size
int
Size of the marker for detected fibres. Defaults to None.
None
axis
int
Specifies the axis, or dimension, along which to slice. Defaults to 0.
0
cmap
str
Specifies the color map for the image. Defaults to \"gray\".
'gray'
img_height
int
Height of the figure. Defaults to 5.
5
img_width
int
Width of the figure. Defaults to 5.
5
Returns:
Name Type Description slicer_obj
interactive
The interactive widget for visualizing slices of a 3D volume.
Example import fibretracker as ft\n\n# Load the volume and visualize the slices\nvol = ft.io.load(\"path/to/volume.txm\")\nft.viz.slicer(vol)\n
import fibretracker as ft\n\n# Load the volume and detected coordinates\nvol = ft.io.load(\"path/to/volume.txm\")\nvol = ft.io.normalize(vol)\nvol = vol[100:350] # 250 slices along the z-axis\ndetect_coords = ft.models.get_fibre_coords(vol)\nft.viz.slicer(vol, detect_coords=detect_coords, mark_size=4)\n
Source code in fibretracker/viz/visualize.py
def slicer(\n vol: np.ndarray,\n detect_coords: Optional[List[np.ndarray]] = None,\n mark_size: Optional[int] = None,\n axis: int = 0,\n cmap: str = \"gray\",\n img_height: int = 5,\n img_width: int = 5, \n) -> widgets.interactive:\n \"\"\"Interactive widget for visualizing slices of a 3D volume and fibres centre if provided.\n\n Args:\n vol (np.ndarray): The 3D volume to be sliced.\n detect_coords (list, optional): List of coordinates of detected fibres. Defaults to None.\n mark_size (int, optional): Size of the marker for detected fibres. Defaults to None.\n axis (int, optional): Specifies the axis, or dimension, along which to slice. Defaults to 0.\n cmap (str, optional): Specifies the color map for the image. Defaults to \"gray\".\n img_height (int, optional): Height of the figure. Defaults to 5.\n img_width (int, optional): Width of the figure. Defaults to 5.\n\n Returns:\n slicer_obj (widgets.interactive): The interactive widget for visualizing slices of a 3D volume.\n\n Example:\n ```python\n import fibretracker as ft\n\n # Load the volume and visualize the slices\n vol = ft.io.load(\"path/to/volume.txm\")\n ft.viz.slicer(vol)\n ```\n \n\n ```python\n import fibretracker as ft\n\n # Load the volume and detected coordinates\n vol = ft.io.load(\"path/to/volume.txm\")\n vol = ft.io.normalize(vol)\n vol = vol[100:350] # 250 slices along the z-axis\n detect_coords = ft.models.get_fibre_coords(vol)\n ft.viz.slicer(vol, detect_coords=detect_coords, mark_size=4)\n ```\n\n \n\n \"\"\"\n\n if detect_coords is None:\n fig, ax = plt.subplots(figsize=(img_width, img_height))\n ax.axis(\"off\")\n else:\n fig, ax = plt.subplots(1, 2, figsize=(2*img_width, img_height), sharex=True, sharey=True, gridspec_kw={'wspace': 0})\n ax[0].axis(\"off\")\n ax[1].axis(\"off\")\n\n def _slice(slice_idx):\n slice_img = vol.take(slice_idx, axis=axis)\n if detect_coords is not None:\n [l.remove() for l in ax[1].lines]\n ax[0].imshow(slice_img, cmap=cmap)\n ax[1].imshow(slice_img, cmap=cmap)\n if mark_size is not None:\n ax[1].plot(detect_coords[slice_idx][:, 0], detect_coords[slice_idx][:, 1], 'rx', markersize=mark_size)\n else:\n ax[1].plot(detect_coords[slice_idx][:, 0], detect_coords[slice_idx][:, 1], 'rx', markersize=3)\n else:\n ax.imshow(slice_img, cmap=cmap)\n\n def on_release(event):\n if detect_coords is not None:\n xlim = ax[0].get_xlim()\n ylim = ax[0].get_ylim()\n ax[1].set_xlim(xlim)\n ax[1].set_ylim(ylim)\n else:\n xlim = ax.get_xlim()\n ylim = ax.get_ylim()\n\n slice_slider = widgets.IntSlider(\n value=vol.shape[axis] // 2,\n min=0,\n max=vol.shape[axis] - 1,\n description=\"Slice\",\n continuous_update=True,\n )\n\n slice_slider.style.description_width = 'middle' # Set the width of the description to fit the larger font size\n slice_slider.style.handle_color = 'blue' # Optional: Change the handle color\n slice_slider.style.font_size = '150px' \n\n fig.canvas.mpl_connect('button_release_event', on_release)\n slicer_obj = interactive(_slice, slice_idx = slice_slider)\n\n return slicer_obj\n
"},{"location":"viz/#fibretracker.viz.plot_tracks","title":"fibretracker.viz.plot_tracks","text":"plot_tracks(tracks, grid=False)\n
Plot tracks of fibres detected in the volume
Parameters:
Name Type Description Default tracks
List[ndarray]
List of arrays of shape (n_points, 3)
required grid
bool
Whether to show grid in the plot
False
Returns:
Name Type Description fig
Figure
matplotlib figure object
Example import fibretracker as ft\n\n# Load the volume and detected coordinates\nvol = ft.io.load(\"path/to/volume.txm\")\nvol = ft.io.normalize(vol)\nvol = vol[100:350] # 250 slices along the z-axis\ndetect_coords = ft.models.get_fibre_coords(vol)\ntracks_gauss = ft.models.track_fibres(coords=detect_coords, smoothtrack_gaussian=True)\nft.viz.plot_tracks(tracks_gauss)\n
Source code in fibretracker/viz/plotting.py
def plot_tracks(\n tracks: List[np.ndarray],\n grid: bool = False,):\n\n '''Plot tracks of fibres detected in the volume\n\n Args:\n tracks: List of arrays of shape (n_points, 3)\n grid: Whether to show grid in the plot\n\n Returns:\n fig (matplotlib.figure.Figure): matplotlib figure object\n\n Example:\n ```python\n import fibretracker as ft\n\n # Load the volume and detected coordinates\n vol = ft.io.load(\"path/to/volume.txm\")\n vol = ft.io.normalize(vol)\n vol = vol[100:350] # 250 slices along the z-axis\n detect_coords = ft.models.get_fibre_coords(vol)\n tracks_gauss = ft.models.track_fibres(coords=detect_coords, smoothtrack_gaussian=True)\n ft.viz.plot_tracks(tracks_gauss)\n ```\n\n \n\n\n '''\n fig, ax = plt.subplots(figsize=(10, 10))\n ax = fig.add_subplot(projection='3d')\n for track in tracks:\n ax.plot(track[:,0], track[:,1], track[:,2])\n ax.grid(grid)\n ax.set_aspect('equal')\n\n plt.show()\n return fig\n
"},{"location":"notebooks/fibre_tracking/","title":"Example","text":"In\u00a0[1]: Copied! %matplotlib widget\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport fibretracker as ft\n
%matplotlib widget import numpy as np import matplotlib.pyplot as plt import fibretracker as ft In\u00a0[2]: Copied! data_path = '/Users/pooja/Documents/PhD_work/ICPR_docs/data/Mock_UD_GFRP_data/UD-01_FoV_2_B2_recon.txm'\ndata_path1 = 'data/Mock_UD_GFRP_data/Mock-01_FoV_2_B2_recon.txm'\ndata_path2 = 'data/Mock_UD_GFRP_data/GFRP'\ndata_path3 = 'data/Mock_UD_GFRP_data/XCT_LR'\n\nV_UD = ft.io.load(data_path)\n# V_Mock = ft.io.load(data_path1)\n# V_GFRP = ft.io.load(data_path2, contains='.tif')\n# V_XCTLR = ft.io.load(data_path3, contains='.tif')\n\nV_norm = ft.io.normalize(V_UD).astype(float)\n
data_path = '/Users/pooja/Documents/PhD_work/ICPR_docs/data/Mock_UD_GFRP_data/UD-01_FoV_2_B2_recon.txm' data_path1 = 'data/Mock_UD_GFRP_data/Mock-01_FoV_2_B2_recon.txm' data_path2 = 'data/Mock_UD_GFRP_data/GFRP' data_path3 = 'data/Mock_UD_GFRP_data/XCT_LR' V_UD = ft.io.load(data_path) # V_Mock = ft.io.load(data_path1) # V_GFRP = ft.io.load(data_path2, contains='.tif') # V_XCTLR = ft.io.load(data_path3, contains='.tif') V_norm = ft.io.normalize(V_UD).astype(float) astropy module not found\n
In\u00a0[3]: Copied! ft.viz.slicer(V_norm, img_height=7, img_width=7, cmap='gray')\n
ft.viz.slicer(V_norm, img_height=7, img_width=7, cmap='gray') Out[3]: interactive(children=(IntSlider(value=499, description='Slice', max=998, style=SliderStyle(description_width='\u2026
Figure In\u00a0[4]: Copied! V_tmp = V_norm[100:350, V_norm.shape[1]//2 - 250:V_norm.shape[1]//2 + 250, V_norm.shape[2]//2 - 250:V_norm.shape[2]//2 + 250]\n
V_tmp = V_norm[100:350, V_norm.shape[1]//2 - 250:V_norm.shape[1]//2 + 250, V_norm.shape[2]//2 - 250:V_norm.shape[2]//2 + 250] In\u00a0[5]: Copied! ft.viz.slicer(V_tmp, img_height=7, img_width=7, cmap='gray')\n
ft.viz.slicer(V_tmp, img_height=7, img_width=7, cmap='gray') Out[5]: interactive(children=(IntSlider(value=125, description='Slice', max=249, style=SliderStyle(description_width='\u2026
Figure In\u00a0[6]: Copied! ft.viz.orthogonal(V_tmp, img_height=7, img_width=7, cmap='gray')\n
ft.viz.orthogonal(V_tmp, img_height=7, img_width=7, cmap='gray') Out[6]: interactive(children=(HBox(children=(IntSlider(value=125, description='Z', max=249), IntSlider(value=250, desc\u2026
Figure In\u00a0[7]: Copied! n_bins = int(255*(V_tmp.max() - V_tmp.min()) + 1)\nhist, bins = np.histogram(V_tmp, bins=n_bins)\nbin_width = bins[1] - bins[0]\nfig, ax = plt.subplots(1, figsize=(5, 5))\nax.bar(bins[:-1], hist, width=bin_width)\nax.set_xlabel('Intensity')\nax.set_ylabel('Frequency')\nax.set_title('Histogram of UD section volume')\nplt.show()\n
n_bins = int(255*(V_tmp.max() - V_tmp.min()) + 1) hist, bins = np.histogram(V_tmp, bins=n_bins) bin_width = bins[1] - bins[0] fig, ax = plt.subplots(1, figsize=(5, 5)) ax.bar(bins[:-1], hist, width=bin_width) ax.set_xlabel('Intensity') ax.set_ylabel('Frequency') ax.set_title('Histogram of UD section volume') plt.show() Figure In\u00a0[9]: Copied! coords = ft.models.get_fibre_coords(V_tmp, std=2.5, min_distance=3, threshold_abs=0.6)\n
coords = ft.models.get_fibre_coords(V_tmp, std=2.5, min_distance=3, threshold_abs=0.6) \r
In\u00a0[10]: Copied! ft.viz.slicer(V_tmp, detect_coords=coords, mark_size=3, img_height=7, img_width=7, cmap='gray')\n
ft.viz.slicer(V_tmp, detect_coords=coords, mark_size=3, img_height=7, img_width=7, cmap='gray') Out[10]: interactive(children=(IntSlider(value=125, description='Slice', max=249, style=SliderStyle(description_width='\u2026
Figure In\u00a0[11]: Copied! # fibre can be tracked either directly from the volume or from the detected coordinates, or both[to avoid coordinate detection again]\n\ntracks = ft.models.track_fibres(coords=coords)\ntracks_gauss = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_gaussian=True, sigma=2)\ntracks_ws = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_watershed=True, threshold=0.6)\n\n# tracks = ft.models.track_fibres(V_tmp, smoothtrack_watershed=True, threshold=0.5)\n# tracks = ft.models.track_fibres(V_tmp, smoothtrack_gaussian=True)\n# tracks = ft.models.track_fibres(coords=coords)\n# tracks = ft.models.track_fibres(coords=coords, smoothtrack_gaussian=True)\n
# fibre can be tracked either directly from the volume or from the detected coordinates, or both[to avoid coordinate detection again] tracks = ft.models.track_fibres(coords=coords) tracks_gauss = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_gaussian=True, sigma=2) tracks_ws = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_watershed=True, threshold=0.6) # tracks = ft.models.track_fibres(V_tmp, smoothtrack_watershed=True, threshold=0.5) # tracks = ft.models.track_fibres(V_tmp, smoothtrack_gaussian=True) # tracks = ft.models.track_fibres(coords=coords) # tracks = ft.models.track_fibres(coords=coords, smoothtrack_gaussian=True) Smoothing tracks using Gaussian \nSmoothing tracks using watershed... \nWatershed volume created.\nSmoothing tracks - iteration: 250/250\r
In\u00a0[12]: Copied! ft.viz.plot_tracks(tracks)\n
ft.viz.plot_tracks(tracks) Figure Out[12]: (<Figure size 1000x1000 with 2 Axes>, <Axes3D: >)
In\u00a0[13]: Copied! ft.viz.plot_tracks(tracks_gauss)\n
ft.viz.plot_tracks(tracks_gauss) Figure Out[13]: (<Figure size 1000x1000 with 2 Axes>, <Axes3D: >)
In\u00a0[14]: Copied! ft.viz.plot_tracks(tracks_ws)\n
ft.viz.plot_tracks(tracks_ws) Figure Out[14]: (<Figure size 1000x1000 with 2 Axes>, <Axes3D: >)
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"FibreTracker","text":"A python library to track fibre in a volume
"},{"location":"#getting-started","title":"\ud83d\udcbb Getting Started","text":"Create a new environment (highly recommended)
Miniconda installation and setup Miniconda is a free lightweight installer for conda.
Here are commands to quickly setup the conda. For reference, you can also use installation link
WindowsmacOSLinux Following commands will install the latest 64-bit version and delete the installer. To install different version change the .exe
version to desired version in the curl
command line.
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe -o miniconda.exe\nstart /wait \"\" miniconda.exe /S\ndel miniconda.exe\n
After successful installation, search and open \"Ananconda prompt (miniconda3)\". Following commands will install the latest 64-bit version and delete the installer. To install different version change the .sh
version to desired version in the curl
command line.
mkdir -p ~/miniconda3\ncurl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o ~/miniconda3/miniconda.sh\nbash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3\nrm -rf ~/miniconda3/miniconda.sh\n
After successful installation, initialize your miniconda (in general, it is intialized; just close the current terminal and open a new terminal). If not, following commands initialize for bash and zsh shells :
~/miniconda3/bin/conda init bash\n~/miniconda3/bin/conda init zsh\n
Following commands will install the latest 64-bit version and delete the installer. To install different version change the .sh
version to desired version in the wget
command line.
mkdir -p ~/miniconda3\nwget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh\nbash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3\nrm -rf ~/miniconda3/miniconda.sh\n
After installing, initialize your newly-installed Miniconda (in general, it is initialized; just close the current terminal and open a new terminal). If not, following commands initialize for bash and zsh shells:
~/miniconda3/bin/conda init bash\n~/miniconda3/bin/conda init zsh\n
Once installed, create the environment
conda create -n fibretracker python=3.11\n
Activate the environment by running
conda activate fibretracker\n
To read .txm file, install dxchange
using conda
[install before fibretracker module to avoid version conflicts and related error]
conda install -c conda-forge dxchange\n
Install the FibreTracker tool using pip
pip install fibretracker\n
Open jupyter notebook and create a new notebook
jupyter notebook\n
Go to Example and run the notebook with fibretracker
enviroment
"},{"location":"#data","title":"Data","text":"Following are the dataset for which fibre tracking is tested on 250 slices
- Mock and UD [link] -
UD-01_FoV_2_B2_recon.txm
Mock-01_FoV_2_B2_recon.txm
- GFRP [link] -
GFRP_Initial.zip
- XCT Low-Res [link] -
XCT_L.zip
"},{"location":"#license","title":"License","text":"fibretracker
was created by Kumari Pooja. It is licensed under the terms of the MIT license.
"},{"location":"#credits","title":"Credits","text":"This work is supported by the RELIANCE doctoral network via the Marie Sk\u0142odowska-Curie Actions HORIZON-MSCA-2021-DN- 01. Project no: 101073040
Project based on the cookiecutter data science project template. #cookiecutterdatascience
"},{"location":"CHANGELOG/","title":"Versions History","text":""},{"location":"CHANGELOG/#v010-20062024","title":"v0.1.0 (20/06/2024)","text":" - First release of
fibretracker
!
"},{"location":"detector/","title":"Documention for fibre detection","text":"To detect fibre centre in a slice
"},{"location":"detector/#fibretracker.models","title":"fibretracker.models","text":""},{"location":"detector/#fibretracker.models.get_fibre_coords","title":"fibretracker.models.get_fibre_coords","text":"get_fibre_coords(vol, std=2.5, min_distance=3, threshold_abs=0.4, weighted_avg=False, window_size=10, apply_filter=False)\n
Get list of fibres centre coordinates in a volume using blob detector
Parameters:
Name Type Description Default vol
ndarray
input volume
required std
float
standard deviation of the Gaussian filter
2.5
min_distance
int
minimum distance between fibres
3
threshold_abs
float
threshold value for the peak from the background
0.4
weighted_avg
bool
whether to apply weighted average to the detected coordinates
False
window_size
int
size of the neighbourhood window around the peak
10
apply_filter
bool
whether to apply Gaussian filter to the window
False
Returns:
Name Type Description coords
List(array)
List of fibres centre coordinates in the volume
Example import fibretracker as ft\n\nvol = ft.detector.get_fib_coords(vol, std=2.5, min_distance=3, threshold_abs=0.4)\n
Source code in fibretracker/models/detector.py
def get_fibre_coords(\n vol: np.ndarray, \n std: float=2.5, \n min_distance: int=3, \n threshold_abs: float=0.4,\n weighted_avg: bool=False,\n window_size: int=10,\n apply_filter: bool=False,\n ):\n ''' Get list of fibres centre coordinates in a volume using blob detector\n\n Args:\n vol: input volume\n std: standard deviation of the Gaussian filter\n min_distance: minimum distance between fibres\n threshold_abs: threshold value for the peak from the background\n weighted_avg: whether to apply weighted average to the detected coordinates\n window_size: size of the neighbourhood window around the peak\n apply_filter: whether to apply Gaussian filter to the window\n\n Returns:\n coords (List(nd.array)): List of fibres centre coordinates in the volume\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.detector.get_fib_coords(vol, std=2.5, min_distance=3, threshold_abs=0.4)\n ```\n\n '''\n coords = []\n for i, im in enumerate(vol):\n coord = blob_centre_detector(im, std=std, min_distance=min_distance, threshold_abs=threshold_abs)\n if weighted_avg:\n coord = avg_fibre_coord(coord, im, window_size=window_size, apply_filter=apply_filter, std=std)\n coords.append(np.stack([coord[:,1], coord[:,0], np.ones(len(coord)) * i], axis=1))\n print(f'Detecting coordinates - slice: {i+1}/{len(vol)}', end='\\r')\n print(' ' * len(f'Detecting coordinates - slice: {i+1}/{len(vol)}'), end='\\r')\n return coords\n
"},{"location":"detector/#fibretracker.models.blob_centre_detector","title":"fibretracker.models.blob_centre_detector","text":"blob_centre_detector(im, std=2.5, min_distance=3, threshold_abs=0.4)\n
Predict coordinates of fibres centre in a volume slice using blob detector
Parameters:
Name Type Description Default im
ndarray
input image
required std
float
standard deviation of the Gaussian filter
2.5
min_distance
int
minimum distance between peaks
3
threshold_abs
float
threshold value for the peak from the background
0.4
Returns:
Name Type Description pred_coords
ndarray
predicted coordinates of the fibre centre
Example import fibretracker as ft\n\nvol = ft.detector.blob_centre_detector(im, std=2.5, min_distance=3, threshold_abs=0.4)\n
Source code in fibretracker/models/detector.py
def blob_centre_detector(\n im: np.ndarray, \n std: float=2.5, \n min_distance: int=3, \n threshold_abs: float=0.4\n ):\n ''' Predict coordinates of fibres centre in a volume slice using blob detector\n\n Args: \n im: input image\n std: standard deviation of the Gaussian filter\n min_distance: minimum distance between peaks\n threshold_abs: threshold value for the peak from the background\n\n Returns: \n pred_coords (np.ndarray): predicted coordinates of the fibre centre\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.detector.blob_centre_detector(im, std=2.5, min_distance=3, threshold_abs=0.4)\n ```\n\n '''\n g = gauss_filter(std)[0]\n im_g = scipy.ndimage.convolve(scipy.ndimage.convolve(im, g), g.T)\n pred_coords = skimage.feature.peak_local_max(im_g, min_distance=min_distance, threshold_abs=threshold_abs)\n return pred_coords\n
"},{"location":"detector/#fibretracker.models.gauss_filter","title":"fibretracker.models.gauss_filter","text":"gauss_filter(std)\n
Generate a 1D Gaussian filter and its derivatives
Parameters:
Name Type Description Default std
float
standard deviation of the Gaussian filter
required Returns:
Name Type Description g
ndarray
1D Gaussian filter
dg
ndarray
derivative of the Gaussian filter
ddg
ndarray
second derivative of the Gaussian filter
Example import fibretracker as ft\n\nvol = ft.detector.gauss_filter(std=2.5)\n
Source code in fibretracker/models/detector.py
def gauss_filter(\n std: float\n ):\n ''' Generate a 1D Gaussian filter and its derivatives\n\n Args: \n std: standard deviation of the Gaussian filter\n\n Returns:\n g (np.ndarray): 1D Gaussian filter\n dg (np.ndarray): derivative of the Gaussian filter\n ddg (np.ndarray): second derivative of the Gaussian filter\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.detector.gauss_filter(std=2.5)\n ```\n\n '''\n x = np.arange(-np.ceil(5*std), np.ceil(5*std) + 1)[:,None]\n g = np.exp(-x**2/(2*std**2))\n g /= np.sum(g)\n dg = -x/std**2 * g\n ddg = -g/std**2 -x/std**2 * dg\n return g, dg, ddg\n
"},{"location":"detector/#fibretracker.models.avg_fibre_coord","title":"fibretracker.models.avg_fibre_coord","text":"avg_fibre_coord(pred_coord, im, window_size=10, apply_filter=False, std=None)\n
Recompute the fibre centre in a slice using weighted average of peak neighbourhood
Parameters:
Name Type Description Default pred_coord
ndarray
predicted coordinates of the peaks
required im
ndarray
input image
required window_size
int
size of the neighbourhood window around the peak
10
apply_filter
bool
whether to apply Gaussian filter to the window
False
std
Optional[float]
standard deviation of the Gaussian filter
None
Returns:
Name Type Description coords
ndarray
recomputed fibre centre coordinates in the slice with weighted average
Example import fibretracker as ft\n\navg_coord = ft.detector.avg_fib_coord(pred_coord, im, window_size)\n
Source code in fibretracker/models/detector.py
def avg_fibre_coord(\n pred_coord: np.ndarray, \n im: np.ndarray, \n window_size: int = 10,\n apply_filter: bool = False,\n std: Optional[float] = None\n ):\n ''' Recompute the fibre centre in a slice using weighted average of peak neighbourhood\n\n Args: \n pred_coord: predicted coordinates of the peaks\n im: input image\n window_size: size of the neighbourhood window around the peak\n apply_filter: whether to apply Gaussian filter to the window\n std: standard deviation of the Gaussian filter\n\n Returns:\n coords (np.ndarray): recomputed fibre centre coordinates in the slice with weighted average\n\n Example:\n ```python\n import fibretracker as ft\n\n avg_coord = ft.detector.avg_fib_coord(pred_coord, im, window_size)\n ```\n\n '''\n coords = []\n for coord in pred_coord:\n x, y = coord\n window = im[x-window_size//2:x+window_size//2+1, y-window_size//2:y+window_size//2+1]\n # Apply Gaussian filter to the window\n if apply_filter:\n if std is not None:\n g = gauss_filter(std)[0]\n else:\n g = gauss_filter(std=2.5)[0]\n window = scipy.ndimage.convolve(scipy.ndimage.convolve(window, g), g.T)\n x_coords, y_coords = np.meshgrid(range(x-window_size//2, x+window_size//2+1), range(y-window_size//2, y+window_size//2+1))\n weighted_x = np.sum(window * x_coords) / np.sum(window)\n weighted_y = np.sum(window * y_coords) / np.sum(window)\n coords.append([weighted_x, weighted_y])\n return np.array(coords)\n
"},{"location":"faq/","title":"Frequently Asked Questions","text":""},{"location":"faq/#vizorthogonal-and-vizslicer-are-not-showing-output","title":"viz.orthogonal and viz.slicer are not showing output","text":"Make sure to run %matplotlib widget alongwith other library
"},{"location":"faq/#how-modelstrack_fibres-works","title":"How models.track_fibres works ?","text":"models.track_fibres either requires detected coordinates coords or normalized volume vol. It is suggested to use both if calculated coords available during smoothening to avoid re-compute.
"},{"location":"faq/#can-i-use-it-locally-on-the-laptop-or-pc","title":"Can I use it locally on the laptop or PC?","text":"Yes, this library works locally and does not need very high computing power to use it. Load depends on memory size of data which you are going to use.
FAQ will be updated based on user experiences"},{"location":"io/","title":"Data input and output","text":"
Dealing with volumetric data can be done by fibretracker
for the most common image formats available.
Currently, it is possible to directly load tiff
, h5
, nii
,txm
and common PIL
formats using one single function.
"},{"location":"io/#fibretracker.io","title":"fibretracker.io","text":""},{"location":"io/#fibretracker.io.load","title":"fibretracker.io.load","text":"load(path, dataset_name=None, return_metadata=False, contains=None, force_load=False, dim_order=(2, 1, 0), **kwargs)\n
Load data from the specified file or directory.
Parameters:
Name Type Description Default path
str or PathLike
The path to the file or directory.
required dataset_name
str
Specifies the name of the dataset to be loaded in case multiple dataset exist within the same file. Default is None (only for HDF5 files)
None
return_metadata
bool
Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)
False
contains
str
Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks). Default is None.
None
force_load
bool
If the file size exceeds available memory, a MemoryError is raised. If force_load is True, the error is changed to warning and the loader tries to load it anyway. Default is False.
False
dim_order
tuple
The order of the dimensions in the volume for .vol files. Default is (2,1,0) which corresponds to (z,y,x)
(2, 1, 0)
**kwargs
Additional keyword arguments to be passed
{}
Returns:
Name Type Description vol
ndarray
The loaded volume If return_metadata=True
and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns tuple
(volume, metadata).
Raises:
Type Description MemoryError
if the given file size exceeds available memory
Example # Load volume from a single file\nimport fibretracker as ft\n\nvol = ft.io.load(data_path)\n
# Load a stack of TIFF files as a volume\nimport fibretracker as ft\n\nvol = ft.io.load(data_path, contains='.tif')\n
Source code in fibretracker/io/read_file.py
def load(\n path,\n dataset_name=None,\n return_metadata=False,\n contains=None,\n force_load: bool = False,\n dim_order=(2, 1, 0),\n **kwargs,\n):\n \"\"\"\n Load data from the specified file or directory.\n\n Args:\n path (str or os.PathLike): The path to the file or directory.\n dataset_name (str, optional): Specifies the name of the dataset to be loaded\n in case multiple dataset exist within the same file. Default is None (only for HDF5 files)\n return_metadata (bool, optional): Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)\n contains (str, optional): Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks).\n Default is None.\n force_load (bool, optional): If the file size exceeds available memory, a MemoryError is raised.\n If force_load is True, the error is changed to warning and the loader tries to load it anyway. Default is False.\n dim_order (tuple, optional): The order of the dimensions in the volume for .vol files. Default is (2,1,0) which corresponds to (z,y,x)\n **kwargs: Additional keyword arguments to be passed\n to the DataLoader constructor.\n\n Returns:\n vol (numpy.ndarray): The loaded volume\n If `return_metadata=True` and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns `tuple` (volume, metadata).\n\n Raises:\n MemoryError: if the given file size exceeds available memory\n\n Example:\n ```python\n # Load volume from a single file\n import fibretracker as ft\n\n vol = ft.io.load(data_path)\n ```\n ```python\n # Load a stack of TIFF files as a volume\n import fibretracker as ft\n\n vol = ft.io.load(data_path, contains='.tif')\n ```\n\n \"\"\"\n\n loader = DataLoader(\n dataset_name=dataset_name,\n return_metadata=return_metadata,\n contains=contains,\n force_load=force_load,\n dim_order=dim_order,\n **kwargs,\n )\n\n data = loader.load(path)\n\n return data\n
"},{"location":"io/#fibretracker.io.normalize","title":"fibretracker.io.normalize","text":"normalize(vol)\n
Normalize the volume to the range [0, 1] using min-max scaling.
Parameters:
Name Type Description Default vol
ndarray
The volume to normalize.
required Returns:
Name Type Description norm_vol
ndarray
The normalized volume.
Example import fibretracker as ft\n\nnorm_vol = ft.io.normalize(vol)\n
Source code in fibretracker/io/read_file.py
def normalize(\n vol: np.ndarray\n ):\n \"\"\"Normalize the volume to the range [0, 1] using min-max scaling.\n\n Args:\n vol (numpy.ndarray): The volume to normalize.\n\n Returns:\n norm_vol (numpy.ndarray): The normalized volume.\n\n Example:\n ```python\n import fibretracker as ft\n\n norm_vol = ft.io.normalize(vol)\n ```\n \"\"\"\n norm_vol = (vol - np.min(vol)) / (np.max(vol) - np.min(vol))\n return norm_vol\n
"},{"location":"tracker/","title":"For tracking file","text":"To detect fibre centre in a slice
"},{"location":"tracker/#fibretracker.models","title":"fibretracker.models","text":""},{"location":"tracker/#fibretracker.models.track_fibres","title":"fibretracker.models.track_fibres","text":"track_fibres(vol=None, max_jump=5, max_skip=5, momentum=0.1, track_min_length=5, coords=None, std=2.5, min_distance=5, threshold_abs=0.5, weighted_avg=False, window_size=10, apply_filter=False, smoothtrack_gaussian=False, sigma=3, smoothtrack_watershed=False, threshold=None)\n
Tracks fibers throughout the volume
Parameters:
Name Type Description Default vol
ndarray
3D volume.
None
max_jump
int
Maximum distance between detected points in two consecutive frames. Threshold in pixels.
5
max_skip
int
Maximum number of frames along one track where no points are detected.
5
momentum
float
Parameter in the range [0;1] that gives momentum to the tracking direction.
0.1
track_min_length
int
Minimum number of points in a track.
5
coords
list
List of numpy arrays with row and column indices of detected points. One per slice, which means that z is gives as the index of the list.
None
std
float
Standard deviation of the Gaussian filter.
2.5
min_distance
int
Minimum distance between fibres.
5
threshold_abs
float
Threshold value for the peak from the background.
0.5
weighted_avg
bool
Whether to apply weighted average to the detected coordinates.
False
window_size
int
Size of the neighbourhood window around the peak.
10
apply_filter
bool
Whether to apply Gaussian filter to the window.
False
smoothtrack_gaussian
bool
Whether to smooth tracks using Gaussian.
False
sigma
float
Sigma value for Gaussian filter.
3
smoothtrack_watershed
bool
Whether to smooth tracks using watershed.
False
threshold
float
Threshold value for watershed.
None
Returns:
Name Type Description tracks
List[ndarray]
List of arrays of shape (n_points, 3) - each list contains coordinates of tracked fibers.
Example import fibretracker as ft\n\nvol = ft.io.load(\"path/to/volume.txm\")\nv = ft.io.normalize(vol)\ncoords = ft.models.get_fibre_coords(v)\ntracks = ft.models.track_fibres(coords=coords)\n
import fibretracker as ft\n\nvol = ft.io.load(\"path/to/volume.txm\")\nv = ft.io.normalize(vol)\ncoords = ft.models.get_fibre_coords(v)\ntracks = ft.models.track_fibres(vol=v, coords=coords, smoothtrack_gaussian=True, sigma=3) # Smoothened tracks using Gaussian\n
Source code in fibretracker/models/tracker.py
def track_fibres(\n vol: Optional[np.ndarray]=None,\n max_jump: int=5, \n max_skip: int=5, \n momentum: float=0.1, \n track_min_length: int=5,\n coords: Optional[List[np.ndarray]]=None,\n std: float=2.5,\n min_distance: int=5,\n threshold_abs: float=0.5,\n weighted_avg: bool=False,\n window_size: int=10,\n apply_filter: bool=False,\n smoothtrack_gaussian: bool=False,\n sigma: float=3,\n smoothtrack_watershed: bool=False,\n threshold: Optional[float]=None\n ):\n '''Tracks fibers throughout the volume\n\n Args:\n vol (np.ndarray, optional): 3D volume.\n max_jump (int, optional): Maximum distance between detected points in two consecutive frames. Threshold in pixels.\n max_skip (int, optional): Maximum number of frames along one track where no points are detected.\n momentum (float, optional): Parameter in the range [0;1] that gives momentum to the tracking direction.\n track_min_length (int, optional): Minimum number of points in a track.\n coords (list, optional): List of numpy arrays with row and column indices of detected points. One per slice, which\n means that z is gives as the index of the list.\n std (float, optional): Standard deviation of the Gaussian filter.\n min_distance (int, optional): Minimum distance between fibres.\n threshold_abs (float, optional): Threshold value for the peak from the background.\n weighted_avg (bool, optional): Whether to apply weighted average to the detected coordinates.\n window_size (int, optional): Size of the neighbourhood window around the peak.\n apply_filter (bool, optional): Whether to apply Gaussian filter to the window.\n smoothtrack_gaussian (bool, optional): Whether to smooth tracks using Gaussian.\n sigma (float, optional): Sigma value for Gaussian filter.\n smoothtrack_watershed (bool, optional): Whether to smooth tracks using watershed.\n threshold (float, optional): Threshold value for watershed.\n\n Returns:\n tracks (List[np.ndarray]): List of arrays of shape (n_points, 3) - each list contains coordinates of tracked fibers.\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.io.load(\"path/to/volume.txm\")\n v = ft.io.normalize(vol)\n coords = ft.models.get_fibre_coords(v)\n tracks = ft.models.track_fibres(coords=coords)\n ```\n ```python\n import fibretracker as ft\n\n vol = ft.io.load(\"path/to/volume.txm\")\n v = ft.io.normalize(vol)\n coords = ft.models.get_fibre_coords(v)\n tracks = ft.models.track_fibres(vol=v, coords=coords, smoothtrack_gaussian=True, sigma=3) # Smoothened tracks using Gaussian\n ```\n\n\n '''\n\n fib_tracker = TrackPoints(max_jump=max_jump, max_skip=max_skip,\n momentum=momentum, track_min_length=track_min_length)\n\n if coords is None:\n coords = get_fibre_coords(vol, std=std, min_distance=min_distance, threshold_abs=threshold_abs, \n weighted_avg=weighted_avg, window_size=window_size, apply_filter=apply_filter)\n\n tracks, _ = fib_tracker(coords)\n if smoothtrack_gaussian:\n print('Smoothing tracks using Gaussian')\n tracks_smooth = []\n for track in tracks:\n tracks_smooth.append(gaussian_filter1d(track, sigma=sigma, axis=0))\n\n return tracks_smooth\n\n elif smoothtrack_watershed and vol is not None:\n print('Smoothing tracks using watershed...')\n tracks_filled = fib_tracker.fill_tracks(tracks)\n if threshold is None:\n threshold = threshold_otsu(vol[len(vol)//2])\n V_thres = vol > threshold\n V_dist = -distance_transform_edt(V_thres)\n V_coords = np.zeros(vol.shape)\n for i, track in enumerate(tracks_filled):\n for point in track:\n V_coords[int(point[2]), int(point[1]), int(point[0])] = i + 1\n V_ws = watershed(V_dist, markers=V_coords.astype(int))*V_thres\n print('Watershed volume created.')\n n_fibers = V_ws.max()\n tracks_smooth = [[] for i in range(n_fibers)]\n\n for i, v_ws in enumerate(V_ws):\n props = regionprops(v_ws)\n for prop in props:\n tracks_smooth[prop.label-1].append(list(prop.centroid[::-1]) + [i])\n print(f'Smoothing tracks - iteration: {i+1}/{len(V_ws)}', end='\\r')\n\n for i in range(n_fibers):\n tracks_smooth[i] = np.array(tracks_smooth[i])\n\n return tracks_smooth\n\n else:\n return tracks\n
"},{"location":"viz/","title":"Visualise detected centre and tracked fibre","text":"To visualise volume accross the slice, detected centres and tracked fibre
"},{"location":"viz/#fibretracker.viz","title":"fibretracker.viz","text":""},{"location":"viz/#fibretracker.viz.orthogonal","title":"fibretracker.viz.orthogonal","text":"orthogonal(vol, cmap='gray', img_height=5, img_width=5)\n
Interactive widget for visualizing orthogonal slices of a 3D volume.
Parameters:
Name Type Description Default vol
ndarray or Tensor
The 3D volume to be sliced.
required cmap
str
Specifies the color map for the image. Defaults to \"gray\".
'gray'
img_height(int,
optional
Height of the figure.
required img_width(int,
optional
Width of the figure.
required Returns:
Name Type Description orthogonal_obj
HBox
The interactive widget for visualizing orthogonal slices of a 3D volume.
Example import fibretracker as ft\n\nvol = ft.io.load(\"path/to/volume.txm\")\nft.viz.orthogonal(vol, cmap=\"gray\")\n
Source code in fibretracker/viz/visualize.py
def orthogonal(\n vol: np.ndarray,\n cmap: str = \"gray\",\n img_height: int = 5,\n img_width: int = 5\n)-> widgets.HBox:\n \"\"\"Interactive widget for visualizing orthogonal slices of a 3D volume.\n\n Args:\n vol (np.ndarray or torch.Tensor): The 3D volume to be sliced.\n cmap (str, optional): Specifies the color map for the image. Defaults to \"gray\".\n img_height(int, optional): Height of the figure.\n img_width(int, optional): Width of the figure.\n\n Returns:\n orthogonal_obj (widgets.HBox): The interactive widget for visualizing orthogonal slices of a 3D volume.\n\n Example:\n ```python\n import fibretracker as ft\n\n vol = ft.io.load(\"path/to/volume.txm\")\n ft.viz.orthogonal(vol, cmap=\"gray\")\n ```\n \n \"\"\"\n\n fig, ax = plt.subplots(1, 3, figsize=(3*img_width, img_height))\n ax[0].axis(\"off\")\n ax[1].axis(\"off\")\n ax[2].axis(\"off\")\n\n def _slice(slice_idx_z, slice_idx_y, slice_idx_x):\n slice_img_z = vol.take(slice_idx_z, axis=0)\n slice_img_y = vol.take(slice_idx_y, axis=1)\n slice_img_x = vol.take(slice_idx_x, axis=2)\n\n ax[0].imshow(slice_img_z, cmap=cmap)\n ax[0].set_aspect('equal')\n ax[1].imshow(slice_img_y, cmap=cmap)\n ax[1].set_aspect('equal')\n ax[2].imshow(slice_img_x, cmap=cmap)\n ax[2].set_aspect('equal')\n\n slice_slider_z = widgets.IntSlider(\n value=vol.shape[0] // 2,\n min=0,\n max=vol.shape[0] - 1,\n description=\"Z\",\n continuous_update=True,\n )\n\n slice_slider_y = widgets.IntSlider(\n value=vol.shape[1] // 2,\n min=0,\n max=vol.shape[1] - 1,\n description=\"Y\",\n continuous_update=True,\n )\n\n slice_slider_x = widgets.IntSlider(\n value=vol.shape[2] // 2,\n min=0,\n max=vol.shape[2] - 1,\n description=\"X\",\n continuous_update=True,\n )\n\n slicer_obj = interactive(_slice, slice_idx_z=slice_slider_z, slice_idx_y=slice_slider_y, slice_idx_x=slice_slider_x)\n\n # Create a horizontal box for the sliders\n hbox = widgets.HBox([slicer_obj.children[0], slicer_obj.children[1], slicer_obj.children[2]], layout=widgets.Layout(align_items=\"stretch\", justify_content=\"center\", align_content=\"center\", justify_items=\"center\", justify_self=\"center\", align_self=\"center\", width=\"100%\"))\n\n # Replace the sliders in the interactive widget with the horizontal box\n slicer_obj.children = (hbox,) + slicer_obj.children[3:]\n\n return slicer_obj\n
"},{"location":"viz/#fibretracker.viz.slicer","title":"fibretracker.viz.slicer","text":"slicer(vol, detect_coords=None, mark_size=None, axis=0, cmap='gray', img_height=5, img_width=5)\n
Interactive widget for visualizing slices of a 3D volume and fibres centre if provided.
Parameters:
Name Type Description Default vol
ndarray
The 3D volume to be sliced.
required detect_coords
list
List of coordinates of detected fibres. Defaults to None.
None
mark_size
int
Size of the marker for detected fibres. Defaults to None.
None
axis
int
Specifies the axis, or dimension, along which to slice. Defaults to 0.
0
cmap
str
Specifies the color map for the image. Defaults to \"gray\".
'gray'
img_height
int
Height of the figure. Defaults to 5.
5
img_width
int
Width of the figure. Defaults to 5.
5
Returns:
Name Type Description slicer_obj
interactive
The interactive widget for visualizing slices of a 3D volume.
Example import fibretracker as ft\n\n# Load the volume and visualize the slices\nvol = ft.io.load(\"path/to/volume.txm\")\nft.viz.slicer(vol)\n
import fibretracker as ft\n\n# Load the volume and detected coordinates\nvol = ft.io.load(\"path/to/volume.txm\")\nvol = ft.io.normalize(vol)\nvol = vol[100:350] # 250 slices along the z-axis\ndetect_coords = ft.models.get_fibre_coords(vol)\nft.viz.slicer(vol, detect_coords=detect_coords, mark_size=4)\n
Source code in fibretracker/viz/visualize.py
def slicer(\n vol: np.ndarray,\n detect_coords: Optional[List[np.ndarray]] = None,\n mark_size: Optional[int] = None,\n axis: int = 0,\n cmap: str = \"gray\",\n img_height: int = 5,\n img_width: int = 5, \n) -> widgets.interactive:\n \"\"\"Interactive widget for visualizing slices of a 3D volume and fibres centre if provided.\n\n Args:\n vol (np.ndarray): The 3D volume to be sliced.\n detect_coords (list, optional): List of coordinates of detected fibres. Defaults to None.\n mark_size (int, optional): Size of the marker for detected fibres. Defaults to None.\n axis (int, optional): Specifies the axis, or dimension, along which to slice. Defaults to 0.\n cmap (str, optional): Specifies the color map for the image. Defaults to \"gray\".\n img_height (int, optional): Height of the figure. Defaults to 5.\n img_width (int, optional): Width of the figure. Defaults to 5.\n\n Returns:\n slicer_obj (widgets.interactive): The interactive widget for visualizing slices of a 3D volume.\n\n Example:\n ```python\n import fibretracker as ft\n\n # Load the volume and visualize the slices\n vol = ft.io.load(\"path/to/volume.txm\")\n ft.viz.slicer(vol)\n ```\n \n\n ```python\n import fibretracker as ft\n\n # Load the volume and detected coordinates\n vol = ft.io.load(\"path/to/volume.txm\")\n vol = ft.io.normalize(vol)\n vol = vol[100:350] # 250 slices along the z-axis\n detect_coords = ft.models.get_fibre_coords(vol)\n ft.viz.slicer(vol, detect_coords=detect_coords, mark_size=4)\n ```\n\n \n\n \"\"\"\n\n if detect_coords is None:\n fig, ax = plt.subplots(figsize=(img_width, img_height))\n ax.axis(\"off\")\n else:\n fig, ax = plt.subplots(1, 2, figsize=(2*img_width, img_height), sharex=True, sharey=True, gridspec_kw={'wspace': 0})\n ax[0].axis(\"off\")\n ax[1].axis(\"off\")\n\n def _slice(slice_idx):\n slice_img = vol.take(slice_idx, axis=axis)\n if detect_coords is not None:\n [l.remove() for l in ax[1].lines]\n ax[0].imshow(slice_img, cmap=cmap)\n ax[1].imshow(slice_img, cmap=cmap)\n if mark_size is not None:\n ax[1].plot(detect_coords[slice_idx][:, 0], detect_coords[slice_idx][:, 1], 'rx', markersize=mark_size)\n else:\n ax[1].plot(detect_coords[slice_idx][:, 0], detect_coords[slice_idx][:, 1], 'rx', markersize=3)\n else:\n ax.imshow(slice_img, cmap=cmap)\n\n def on_release(event):\n if detect_coords is not None:\n xlim = ax[0].get_xlim()\n ylim = ax[0].get_ylim()\n ax[1].set_xlim(xlim)\n ax[1].set_ylim(ylim)\n else:\n xlim = ax.get_xlim()\n ylim = ax.get_ylim()\n\n slice_slider = widgets.IntSlider(\n value=vol.shape[axis] // 2,\n min=0,\n max=vol.shape[axis] - 1,\n description=\"Slice\",\n continuous_update=True,\n )\n\n slice_slider.style.description_width = 'middle' # Set the width of the description to fit the larger font size\n slice_slider.style.handle_color = 'blue' # Optional: Change the handle color\n slice_slider.style.font_size = '150px' \n\n fig.canvas.mpl_connect('button_release_event', on_release)\n slicer_obj = interactive(_slice, slice_idx = slice_slider)\n\n return slicer_obj\n
"},{"location":"viz/#fibretracker.viz.plot_tracks","title":"fibretracker.viz.plot_tracks","text":"plot_tracks(tracks, grid=False)\n
Plot tracks of fibres detected in the volume
Parameters:
Name Type Description Default tracks
List[ndarray]
List of arrays of shape (n_points, 3)
required grid
bool
Whether to show grid in the plot
False
Returns:
Name Type Description fig
Figure
matplotlib figure object
Example import fibretracker as ft\n\n# Load the volume and detected coordinates\nvol = ft.io.load(\"path/to/volume.txm\")\nvol = ft.io.normalize(vol)\nvol = vol[100:350] # 250 slices along the z-axis\ndetect_coords = ft.models.get_fibre_coords(vol)\ntracks_gauss = ft.models.track_fibres(coords=detect_coords, smoothtrack_gaussian=True)\nft.viz.plot_tracks(tracks_gauss)\n
Source code in fibretracker/viz/plotting.py
def plot_tracks(\n tracks: List[np.ndarray],\n grid: bool = False,):\n\n '''Plot tracks of fibres detected in the volume\n\n Args:\n tracks: List of arrays of shape (n_points, 3)\n grid: Whether to show grid in the plot\n\n Returns:\n fig (matplotlib.figure.Figure): matplotlib figure object\n\n Example:\n ```python\n import fibretracker as ft\n\n # Load the volume and detected coordinates\n vol = ft.io.load(\"path/to/volume.txm\")\n vol = ft.io.normalize(vol)\n vol = vol[100:350] # 250 slices along the z-axis\n detect_coords = ft.models.get_fibre_coords(vol)\n tracks_gauss = ft.models.track_fibres(coords=detect_coords, smoothtrack_gaussian=True)\n ft.viz.plot_tracks(tracks_gauss)\n ```\n\n \n\n\n '''\n fig, ax = plt.subplots(figsize=(10, 10))\n ax = fig.add_subplot(projection='3d')\n for track in tracks:\n ax.plot(track[:,0], track[:,1], track[:,2])\n ax.grid(grid)\n ax.set_aspect('equal')\n\n plt.show()\n return fig\n
"},{"location":"notebooks/fibre_tracking/","title":"Example","text":"In\u00a0[1]: Copied! %matplotlib widget\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport fibretracker as ft\n
%matplotlib widget import numpy as np import matplotlib.pyplot as plt import fibretracker as ft In\u00a0[2]: Copied! data_path = '/Users/pooja/Documents/PhD_work/ICPR_docs/data/Mock_UD_GFRP_data/UD-01_FoV_2_B2_recon.txm'\ndata_path1 = 'data/Mock_UD_GFRP_data/Mock-01_FoV_2_B2_recon.txm'\ndata_path2 = 'data/Mock_UD_GFRP_data/GFRP'\ndata_path3 = 'data/Mock_UD_GFRP_data/XCT_LR'\n\nV_UD = ft.io.load(data_path)\n# V_Mock = ft.io.load(data_path1)\n# V_GFRP = ft.io.load(data_path2, contains='.tif')\n# V_XCTLR = ft.io.load(data_path3, contains='.tif')\n\nV_norm = ft.io.normalize(V_UD).astype(float)\n
data_path = '/Users/pooja/Documents/PhD_work/ICPR_docs/data/Mock_UD_GFRP_data/UD-01_FoV_2_B2_recon.txm' data_path1 = 'data/Mock_UD_GFRP_data/Mock-01_FoV_2_B2_recon.txm' data_path2 = 'data/Mock_UD_GFRP_data/GFRP' data_path3 = 'data/Mock_UD_GFRP_data/XCT_LR' V_UD = ft.io.load(data_path) # V_Mock = ft.io.load(data_path1) # V_GFRP = ft.io.load(data_path2, contains='.tif') # V_XCTLR = ft.io.load(data_path3, contains='.tif') V_norm = ft.io.normalize(V_UD).astype(float) astropy module not found\n
In\u00a0[3]: Copied! ft.viz.slicer(V_norm, img_height=7, img_width=7, cmap='gray')\n
ft.viz.slicer(V_norm, img_height=7, img_width=7, cmap='gray') Out[3]: interactive(children=(IntSlider(value=499, description='Slice', max=998, style=SliderStyle(description_width='\u2026
Figure In\u00a0[4]: Copied! V_tmp = V_norm[100:350, V_norm.shape[1]//2 - 250:V_norm.shape[1]//2 + 250, V_norm.shape[2]//2 - 250:V_norm.shape[2]//2 + 250]\n
V_tmp = V_norm[100:350, V_norm.shape[1]//2 - 250:V_norm.shape[1]//2 + 250, V_norm.shape[2]//2 - 250:V_norm.shape[2]//2 + 250] In\u00a0[5]: Copied! ft.viz.slicer(V_tmp, img_height=7, img_width=7, cmap='gray')\n
ft.viz.slicer(V_tmp, img_height=7, img_width=7, cmap='gray') Out[5]: interactive(children=(IntSlider(value=125, description='Slice', max=249, style=SliderStyle(description_width='\u2026
Figure In\u00a0[6]: Copied! ft.viz.orthogonal(V_tmp, img_height=7, img_width=7, cmap='gray')\n
ft.viz.orthogonal(V_tmp, img_height=7, img_width=7, cmap='gray') Out[6]: interactive(children=(HBox(children=(IntSlider(value=125, description='Z', max=249), IntSlider(value=250, desc\u2026
Figure In\u00a0[7]: Copied! n_bins = int(255*(V_tmp.max() - V_tmp.min()) + 1)\nhist, bins = np.histogram(V_tmp, bins=n_bins)\nbin_width = bins[1] - bins[0]\nfig, ax = plt.subplots(1, figsize=(5, 5))\nax.bar(bins[:-1], hist, width=bin_width)\nax.set_xlabel('Intensity')\nax.set_ylabel('Frequency')\nax.set_title('Histogram of UD section volume')\nplt.show()\n
n_bins = int(255*(V_tmp.max() - V_tmp.min()) + 1) hist, bins = np.histogram(V_tmp, bins=n_bins) bin_width = bins[1] - bins[0] fig, ax = plt.subplots(1, figsize=(5, 5)) ax.bar(bins[:-1], hist, width=bin_width) ax.set_xlabel('Intensity') ax.set_ylabel('Frequency') ax.set_title('Histogram of UD section volume') plt.show() Figure In\u00a0[9]: Copied! coords = ft.models.get_fibre_coords(V_tmp, std=2.5, min_distance=3, threshold_abs=0.6)\n
coords = ft.models.get_fibre_coords(V_tmp, std=2.5, min_distance=3, threshold_abs=0.6) \r
In\u00a0[10]: Copied! ft.viz.slicer(V_tmp, detect_coords=coords, mark_size=3, img_height=7, img_width=7, cmap='gray')\n
ft.viz.slicer(V_tmp, detect_coords=coords, mark_size=3, img_height=7, img_width=7, cmap='gray') Out[10]: interactive(children=(IntSlider(value=125, description='Slice', max=249, style=SliderStyle(description_width='\u2026
Figure In\u00a0[11]: Copied! # fibre can be tracked either directly from the volume or from the detected coordinates, or both[to avoid coordinate detection again]\n\ntracks = ft.models.track_fibres(coords=coords)\ntracks_gauss = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_gaussian=True, sigma=2)\ntracks_ws = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_watershed=True, threshold=0.6)\n\n# tracks = ft.models.track_fibres(V_tmp, smoothtrack_watershed=True, threshold=0.5)\n# tracks = ft.models.track_fibres(V_tmp, smoothtrack_gaussian=True)\n# tracks = ft.models.track_fibres(coords=coords)\n# tracks = ft.models.track_fibres(coords=coords, smoothtrack_gaussian=True)\n
# fibre can be tracked either directly from the volume or from the detected coordinates, or both[to avoid coordinate detection again] tracks = ft.models.track_fibres(coords=coords) tracks_gauss = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_gaussian=True, sigma=2) tracks_ws = ft.models.track_fibres(V_tmp, coords=coords, smoothtrack_watershed=True, threshold=0.6) # tracks = ft.models.track_fibres(V_tmp, smoothtrack_watershed=True, threshold=0.5) # tracks = ft.models.track_fibres(V_tmp, smoothtrack_gaussian=True) # tracks = ft.models.track_fibres(coords=coords) # tracks = ft.models.track_fibres(coords=coords, smoothtrack_gaussian=True) Smoothing tracks using Gaussian \nSmoothing tracks using watershed... \nWatershed volume created.\nSmoothing tracks - iteration: 250/250\r
In\u00a0[12]: Copied! ft.viz.plot_tracks(tracks)\n
ft.viz.plot_tracks(tracks) Figure Out[12]: (<Figure size 1000x1000 with 2 Axes>, <Axes3D: >)
In\u00a0[13]: Copied! ft.viz.plot_tracks(tracks_gauss)\n
ft.viz.plot_tracks(tracks_gauss) Figure Out[13]: (<Figure size 1000x1000 with 2 Axes>, <Axes3D: >)
In\u00a0[14]: Copied! ft.viz.plot_tracks(tracks_ws)\n
ft.viz.plot_tracks(tracks_ws) Figure Out[14]: (<Figure size 1000x1000 with 2 Axes>, <Axes3D: >)
"}]}
\ No newline at end of file
diff --git a/sitemap.xml b/sitemap.xml
index eacbc5b..4f17efb 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -2,42 +2,42 @@
https://ndpooja.github.io/fibretracker/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/CHANGELOG/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/detector/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/faq/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/io/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/tracker/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/viz/
- 2024-06-20
+ 2024-06-21
daily
https://ndpooja.github.io/fibretracker/notebooks/fibre_tracking/
- 2024-06-20
+ 2024-06-21
daily
\ No newline at end of file
diff --git a/sitemap.xml.gz b/sitemap.xml.gz
index 5924c1cc3dfc3765a81799e8be35b39329f2934c..584c8baa57aaf46266b4327abc9646a3f0202890 100644
GIT binary patch
delta 260
zcmV+f0sH=!0+#{@ABzYGfWmZ<2OWR9MMR~|BBJX-^rB};lW7~b&2*FOR{iy+?IOJ|
zLY+%8kC(^CKqlLKwoP;d>ol62tZ70bFcOtERZiYsAL1*r;j8Rm8wWlLX5(^Fd*9tK
z*7rSi+CwWkN6}Wy$vQNSokW(Vh`H=(}%`lTcOmmhT0--~B7=%GN|xk-K>^{^!W9(+8)^5s9P
KLG$RW1pol7$$?z}
delta 260
zcmV+f0sH=!0+#{@ABzYG0C97X2OWQE5m9NgETZc{^rB};lWCjXHq%YATlLqQwu|&G
zLY+%8kC(^CKqgy%v`usZ>ol62T+oC>U?eJSs+_#NKE&5#%~#pcHV%9g%*N%U_P)Di
ztnYj3w1-x7j-suYlXYkuJBuu#H-xXEP(#3U8!Ky2@*%~A7^6DGouHNW^|5rI8d<3e
z3*HL32g@=xnCEYW^DQc#Ch29IT*YY;EN5+IleI7vlok$L3Eg~VY^F?5?1$