forked from napari/napari
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path3D_vectors_through_time.py
More file actions
113 lines (92 loc) · 3.99 KB
/
Copy path3D_vectors_through_time.py
File metadata and controls
113 lines (92 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""
3D vector field and image across time
=====================================
This example is from a mechanical test on a granular material, where multiple 3D volume have been acquired using x-ray tomography during axial loading.
We have used [`spam`](https://www.spam-project.dev/) to label individual particles (with watershed and some tidying up manually), and these particles are tracked through time with 3D "discrete" volume correlation *incrementally*:
t0 → t1 and then t1 → t2.
Although we're also measuring rotations (and strains), but here we're interested to visualise the displacement field on top of the image to spot tracking errors.
.. tags:: visualization-nD
"""
import numpy as np
import pooch
import tifffile
import napari
###############################################################################
# Input data
# -----------
#
# Input data are therefore:
# - A series of 3D greyscale images
# - A series of measured transformations between subsequent pairs of images
# - We also have consistent labels through time which could also be visualised but are not here
#
# Let's download it!
grey_files = sorted(pooch.retrieve(
"doi:10.5281/zenodo.17668709/grey.zip",
known_hash="md5:760be2bad68366872111410776563760",
processor=pooch.Unzip(),
progressbar=True
))
# Load individual 3D images as a 4D with a list comprehension, skipping last one
# result is a T, Z, Y, X 16-bit array
greys = np.array([tifffile.imread(grey_file) for grey_file in grey_files[0:-1]])
# load incremental TSV tracking files from spam-ddic, [::2] is to skip VTK files also in folder
tracking_files = sorted(pooch.retrieve(
"doi:10.5281/zenodo.17668709/ddic.zip",
known_hash="md5:2d7c6a052f53b4a827ff4e4585644fac",
processor=pooch.Unzip(),
progressbar=True
))[::2]
###############################################################################
# Collect data together for napari
#----------------------------------
# We will loop through all the images in order to prepare the necessary data structure for napari
#
# These variables are going to contain coordinates, displacements and lengths (for colouring vectors) for all timesteps
coords_all = []
disps_all = []
lengths_all = []
for t, tracking_file in enumerate(tracking_files):
# load the indicator for convergence
returnStatus = np.genfromtxt(tracking_file, skip_header=1, usecols=(19))
# Load coords and displacements, keeping only converged results (returnStatus==2)
coords = np.genfromtxt(tracking_file, skip_header=1, usecols=(1,2,3))[returnStatus==2]
disps = np.genfromtxt(tracking_file, skip_header=1, usecols=(4,5,6))[returnStatus==2]
# Compute lengths in order to colour vectors
lengths = np.linalg.norm(disps, axis=1)
# Prepend an extra dimension to coordinates to place them in time, and fill it with the incremental t
coords = np.hstack([np.ones((coords.shape[0],1))*t, coords])
# Preprend zeros to the displacements (the "end" of the vector), since they do not displace through time
disps = np.hstack([np.zeros((disps.shape[0],1)), disps])
# Add to lists
coords_all.append(coords)
disps_all.append(disps)
lengths_all.append(lengths)
# Concatenate into arrays
coords_all = np.concatenate(coords_all)
disps_all = np.concatenate(disps_all)
lengths_all = np.concatenate(lengths_all)
# Stack this into an array of size N (individual points) x 2 (vector start and length) x 4 (tzyx)
coords_displacements_all = np.stack([coords_all, disps_all], axis=1)
viewer = napari.Viewer(ndisplay=3)
viewer.add_image(
greys,
contrast_limits=[15000, 50000],
rendering="attenuated_mip",
attenuation=0.333
)
viewer.add_vectors(
coords_displacements_all,
vector_style='arrow',
length=1,
properties={'disp_norm': lengths_all},
edge_colormap='plasma',
edge_width=3,
out_of_slice_display=True,
)
viewer.camera.angles = (0,0,-97)
viewer.camera.orientation = ('away','up','right')
viewer.dims.current_step = (11,199, 124, 124)
viewer.fit_to_view()
if __name__ == '__main__':
napari.run()