Skip to content
Snippets Groups Projects
Commit 1a559c69 authored by vand's avatar vand
Browse files

Update StructureTensor3D_Examples.ipynb

parent 8f3bc1c4
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
 
# 3D structure tensor - a small example
A small example demonstrating the use of 3D structure tensor for visualizing and clustering dominant orientation.
 
%% Cell type:code id: tags:
 
``` python
%matplotlib notebook
import numpy as np
import scipy.io
import st3d
```
 
%% Cell type:markdown id: tags:
 
## Reading the data
 
The data is a small cube from a volumetric image og fibre composite. The cube contains five bundles in layers: UD fibre (0 deg), crossing fibre (45 deg), 90 deg fibre, -45 deg bundle, UD bundle (0 deg).
 
%% Cell type:code id: tags:
 
``` python
volume = scipy.io.loadmat('example_data_3D/multi_cube.mat')['vol']
print(volume.shape)
```
 
%% Output
(150, 150, 150)
%% Cell type:markdown id: tags:
 
## Computing the structure tensor and the dominant orientation
Computation of structure tensor requires only two parameters: the noise scale sigma and the integration scale rho. Parameter sigma controls smothing while computing gradientes, and structures smaller than sigma will be removed by smoothing. Parameter rho gives the size over the neighborhood in which the orientation is to be analysed for every volume voxel. Larger rho will result in a smoother orientation field.
 
Structure tensor is a 3x3 matrix, but as it is symmetrical we only carry values of 6 elements: $s_{xx}$, $s_{yy}$, $s_{zz}$, $s_{xy}$, $s_{xz}$ and $s_{yz}$.
 
Eigenvalues (val) carry the information about the degree of anisotropy - this is not used or visualized here. Eigenvectors (vec) carry the orientation information, as $x$, $y$, and $z$ component of the orientation vector.
 
%% Cell type:code id: tags:
 
``` python
sigma = 0.5; # noise scale
rho = 2; # integration scale
S = st3d.structure_tensor(volume, sigma, rho)
val,vec = st3d.eig_special(S)
print(f'The volume has a shape {volume.shape}, i.e. {volume.size} voxels.')
print(f'Structure tensor information is carried in a {S.shape} array.')
print(f'Orientation information is carried in a {vec.shape} array.')
```
 
%% Output
 
The volume has a shape (150, 150, 150), i.e. 3375000 voxels.
Structure tensor information is carried in a (6, 3375000) array.
Orientation information is carried in a (3, 3375000) array.
 
%% Cell type:markdown id: tags:
 
## Visualizing the dominant orientation
Here we show only dominant orientation, ignoring shape measures.
 
Since slicng is in $z$ direction, the arrows show $x$ and $y$ component of orientation vectors, on top of every slice.
 
To interactively inspect the volume use arrow keys.
 
%% Cell type:code id: tags:
 
``` python
st3d.show_vol_flow(volume, vec[0:2].reshape((2,)+volume.shape), s=10, double_arrow = True)
```
 
%% Output
 
 
 
%% Cell type:markdown id: tags:
 
When visualizing the orientation as color, I choose fan coloring which uses hsv colors for orientatins in a certain plane, here a $xy$ plane,, and gray color for the orientations orthogonal to this plane. This coloring is convenient since all fibre bundles lay in $xy$ plane.
 
%% Cell type:code id: tags:
 
``` python
st3d.show_vol_orientation(volume, vec, coloring = st3d.fan_coloring)
```
 
%% Output
 
 
 
%% Cell type:markdown id: tags:
 
## And again for a rotated sample
The same analysis as above, but for the sample rotated such that layers are in $xz$-plane.
 
%% Cell type:code id: tags:
 
``` python
volume = np.transpose(volume, (1, 0, 2))
S = st3d.structure_tensor(volume, sigma, rho)
val,vec = st3d.eig_special(S)
coloring_z = lambda v : st3d.fan_coloring(v[[2, 0, 1]]) # rotating the coloring function
st3d.show_vol_orientation(volume, vec, coloring = coloring_z)
```
 
%% Output
 
 
 
%% Cell type:markdown id: tags:
 
## Investigating tensor-vector distance
A tensor-vector distance can be computed for every voxel. Here I compute the distance from the z-direction. In the rotated volume, a 90 deg. bundle (the middle layer) is aligned with z-direction, and has the smallest distance.
 
%% Cell type:code id: tags:
 
``` python
u = np.array([0,0,1])
dist = st3d.tensor_vector_distance(S,u)
st3d.show_vol(dist.reshape(volume.shape))
```
 
%% Output
 
 
 
%% Cell type:markdown id: tags:
 
## K-means like clustering of structure tensor using tensor-vector distance
Tensor-vector distance allows clustering tensors using an approach similar to k-means. Here, every cluster is characterized by an orientation vector, and consists of the tensors which have a small distance to this orientation. The advantage of the approach is that it operates on tensors, and does not require their eigendecomposition. Only computation of cluster orientation requires eigendecomposition.
 
%% Cell type:code id: tags:
 
``` python
t = np.sqrt(1/2)
u_clusters = np.array([[1,0,0],[0,0,1],[t,0,t],[-t,0,t]]).T # initalizing orientations close to desired solution
dist = st3d.tensor_vector_distance(S,u_clusters)
assignment = np.argmin(dist,axis = 1)
 
S_clusters = np.zeros((6,u_clusters.shape[1]))
for r in range(10): # iterations of k-means
 
for i in range(u_clusters.shape[1]): # collecting ST for all voxels in a cluster
S_clusters[:,i] = np.mean(S[:,assignment==i],axis=1)
val,vec = st3d.eig_special(S_clusters) # estimating new cluster orientation
print(f'Iter {r}: moved cluster centers for for {np.sqrt(np.sum((u_clusters-vec)**2))}')
u_clusters = vec
dist = st3d.tensor_vector_distance(S,u_clusters)
assignment_new = np.argmin(dist,axis = 1)
print(f'Iter {r}: moved {np.sum(abs(assignment-assignment_new))} voxels')
assignment = assignment_new
 
st3d.show_vol(assignment.reshape(volume.shape), cmap='jet')
```
 
%% Output
 
Iter 0: moved cluster centers for for 3.4611420322311117
Iter 0: moved 39247 voxels
Iter 1: moved cluster centers for for 0.004271292625400079
Iter 1: moved 1943 voxels
Iter 2: moved cluster centers for for 0.0002994716482208428
Iter 2: moved 147 voxels
Iter 3: moved cluster centers for for 2.5064554745549023e-05
Iter 3: moved 12 voxels
Iter 4: moved cluster centers for for 2.299743582546306e-06
Iter 4: moved 0 voxels
Iter 5: moved cluster centers for for 0.0
Iter 5: moved 0 voxels
Iter 6: moved cluster centers for for 0.0
Iter 6: moved 0 voxels
Iter 7: moved cluster centers for for 0.0
Iter 7: moved 0 voxels
Iter 8: moved cluster centers for for 0.0
Iter 8: moved 0 voxels
Iter 9: moved cluster centers for for 0.0
Iter 9: moved 0 voxels
 
 
 
%% Cell type:code id: tags:
 
``` python
```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment