From 399a06502560d9be7b61881b3a9d8cf924cd4f9b Mon Sep 17 00:00:00 2001 From: <> Date: Thu, 20 Jun 2024 16:45:00 +0000 Subject: [PATCH] Deployed e8430c0 with MkDocs version: 1.6.0 --- CHANGELOG/index.html | 10 +-- index.html | 5 +- io/index.html | 168 +++++++++++++++++++-------------------- search/search_index.json | 2 +- 4 files changed, 94 insertions(+), 91 deletions(-) diff --git a/CHANGELOG/index.html b/CHANGELOG/index.html index d547e94..24a905e 100644 --- a/CHANGELOG/index.html +++ b/CHANGELOG/index.html @@ -499,9 +499,9 @@
fibretracker
!Activate the environment by running
+To read .txm file, install dxchange
using conda
[install before fibretracker module to avoid version conflicts and related error]
Install the FibreTracker tool using pip
pip install fibretracker
+
Go to Example and run the notebook with fibretracker
enviroment
Data
diff --git a/io/index.html b/io/index.html
index ecdddb8..a77b307 100644
--- a/io/index.html
+++ b/io/index.html
@@ -855,9 +855,7 @@
Source code in fibretracker/io/read_file.py
- 443
-444
-445
+ def load(
- path,
- dataset_name=None,
- return_metadata=False,
- contains=None,
- force_load: bool = False,
- dim_order=(2, 1, 0),
- **kwargs,
-):
- """
- Load data from the specified file or directory.
-
- Args:
- path (str or os.PathLike): The path to the file or directory.
- dataset_name (str, optional): 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)
- return_metadata (bool, optional): Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)
- contains (str, optional): Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks).
- Default is None.
- force_load (bool, optional): 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.
- 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)
- **kwargs: Additional keyword arguments to be passed
- to the DataLoader constructor.
-
- Returns:
- vol (numpy.ndarray): The loaded volume
- If `return_metadata=True` and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns `tuple` (volume, metadata).
-
- Raises:
- MemoryError: if the given file size exceeds available memory
-
- Example:
- ```python
- # Load volume from a single file
- import fibretracker as ft
-
- vol = ft.io.load(data_path)
- ```
- ```python
- # Load a stack of TIFF files as a volume
- import fibretracker as ft
-
- vol = ft.io.load(data_path, contains='.tif')
- ```
-
- """
+502
+503
+504
def load(
+ path,
+ dataset_name=None,
+ return_metadata=False,
+ contains=None,
+ force_load: bool = False,
+ dim_order=(2, 1, 0),
+ **kwargs,
+):
+ """
+ Load data from the specified file or directory.
+
+ Args:
+ path (str or os.PathLike): The path to the file or directory.
+ dataset_name (str, optional): 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)
+ return_metadata (bool, optional): Specifies whether to return metadata or not. Default is False (only for HDF5 and TXRM/TXM/XRM files)
+ contains (str, optional): Specifies a part of the name that is common for the TIFF file stack to be loaded (only for TIFF stacks).
+ Default is None.
+ force_load (bool, optional): 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.
+ 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)
+ **kwargs: Additional keyword arguments to be passed
+ to the DataLoader constructor.
+
+ Returns:
+ vol (numpy.ndarray): The loaded volume
+ If `return_metadata=True` and file format is either HDF5, NIfTI or TXRM/TXM/XRM, returns `tuple` (volume, metadata).
+
+ Raises:
+ MemoryError: if the given file size exceeds available memory
+
+ Example:
+ ```python
+ # Load volume from a single file
+ import fibretracker as ft
+
+ vol = ft.io.load(data_path)
+ ```
+ ```python
+ # Load a stack of TIFF files as a volume
+ import fibretracker as ft
+
+ vol = ft.io.load(data_path, contains='.tif')
+ ```
- loader = DataLoader(
- dataset_name=dataset_name,
- return_metadata=return_metadata,
- contains=contains,
- force_load=force_load,
- dim_order=dim_order,
- **kwargs,
- )
-
- data = loader.load(path)
+ """
+
+ loader = DataLoader(
+ dataset_name=dataset_name,
+ return_metadata=return_metadata,
+ contains=contains,
+ force_load=force_load,
+ dim_order=dim_order,
+ **kwargs,
+ )
- return data
+ data = loader.load(path)
+
+ return data
@@ -1057,9 +1057,7 @@
Source code in fibretracker/io/read_file.py
- 504
-505
-506
+ def normalize(
- vol: np.ndarray
- ):
- """Normalize the volume to the range [0, 1] using min-max scaling.
-
- Args:
- vol (numpy.ndarray): The volume to normalize.
-
- Returns:
- norm_vol (numpy.ndarray): The normalized volume.
-
- Example:
- ```python
- import fibretracker as ft
-
- norm_vol = ft.io.normalize(vol)
- ```
- """
- norm_vol = (vol - np.min(vol)) / (np.max(vol) - np.min(vol))
- return norm_vol
+523
+524
+525
def normalize(
+ vol: np.ndarray
+ ):
+ """Normalize the volume to the range [0, 1] using min-max scaling.
+
+ Args:
+ vol (numpy.ndarray): The volume to normalize.
+
+ Returns:
+ norm_vol (numpy.ndarray): The normalized volume.
+
+ Example:
+ ```python
+ import fibretracker as ft
+
+ norm_vol = ft.io.normalize(vol)
+ ```
+ """
+ norm_vol = (vol - np.min(vol)) / (np.max(vol) - np.min(vol))
+ return norm_vol
diff --git a/search/search_index.json b/search/search_index.json
index b475a43..5026e71 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
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-14062024","title":"v0.1.0 (14/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)
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