Note
Go to the end to download the full example code. or to run this example in your browser via Binder
Find center of rotation with simulated data#
This tutorial use the synthetic data class to show how it can be possible to use an incremental rotation movie to find the center of rotation, rotation plane angle and rotation plane orientation and then derotate a movie with any angle pattern.
- What happens behind the scenes:
Generate a synthetic image with two cells and two angle patterns, one for incremental pipeline (in steps) and one for testing (a sinusoidal pattern).
Use the Rotator class to derotate the movie with the incremental angle pattern and the sinusoidal angle pattern.
Find the center of rotation by fitting an ellipse to the largest blob for different angle positions.
Derotate the movie with the sinusoidal angle pattern using the center of rotation and ellipse parameters found in the previous step.
We are going to inspect the plots generated during the pipeline to see how the algorithm works and how the center of rotation is found.
This serves only as an illustrative example. To understand how to find the center of rotation with real data, please refer to the Key concepts page in the User guide.
Imports#
from pathlib import Path
import matplotlib.pyplot as plt
from derotation.simulate.synthetic_data import SyntheticData
Define parameters for the synthetic simulation#
rotation_plane_angle = 10 # degrees
rotation_plane_orientation = 30 # degrees
center_of_rotation_offset = (7, -7) # pixels
Run full pipeline#
This will generate simulated rotated data and run an incremental search to find the optimal center of rotation. All intermediate plots are saved in the “debug” folder.
s_data = SyntheticData(
radius=2,
center_of_rotation_offset=center_of_rotation_offset,
rotation_plane_angle=rotation_plane_angle,
rotation_plane_orientation=rotation_plane_orientation,
num_frames=50,
pad=20,
background_value=80,
plots=True,
)
s_data.integration_pipeline()
0%| | 0/50 [00:00<?, ?it/s]
4%|▍ | 2/50 [00:00<00:03, 13.45it/s]
8%|▊ | 4/50 [00:00<00:07, 5.81it/s]
10%|█ | 5/50 [00:00<00:08, 5.21it/s]
12%|█▏ | 6/50 [00:01<00:09, 4.86it/s]
14%|█▍ | 7/50 [00:01<00:09, 4.64it/s]
16%|█▌ | 8/50 [00:01<00:09, 4.49it/s]
18%|█▊ | 9/50 [00:01<00:09, 4.40it/s]
20%|██ | 10/50 [00:02<00:09, 4.33it/s]
22%|██▏ | 11/50 [00:02<00:09, 4.28it/s]
24%|██▍ | 12/50 [00:02<00:08, 4.25it/s]
26%|██▌ | 13/50 [00:02<00:08, 4.22it/s]
28%|██▊ | 14/50 [00:03<00:08, 4.20it/s]
30%|███ | 15/50 [00:03<00:08, 4.19it/s]
32%|███▏ | 16/50 [00:03<00:08, 4.19it/s]
34%|███▍ | 17/50 [00:03<00:07, 4.19it/s]
36%|███▌ | 18/50 [00:03<00:07, 4.19it/s]
38%|███▊ | 19/50 [00:04<00:07, 4.20it/s]
40%|████ | 20/50 [00:04<00:07, 4.20it/s]
42%|████▏ | 21/50 [00:04<00:06, 4.20it/s]
44%|████▍ | 22/50 [00:04<00:06, 4.20it/s]
46%|████▌ | 23/50 [00:05<00:06, 4.20it/s]
48%|████▊ | 24/50 [00:05<00:06, 4.20it/s]
50%|█████ | 25/50 [00:05<00:05, 4.20it/s]
52%|█████▏ | 26/50 [00:05<00:05, 4.20it/s]
54%|█████▍ | 27/50 [00:06<00:05, 4.21it/s]
56%|█████▌ | 28/50 [00:06<00:05, 4.21it/s]
58%|█████▊ | 29/50 [00:06<00:04, 4.21it/s]
60%|██████ | 30/50 [00:06<00:04, 4.21it/s]
62%|██████▏ | 31/50 [00:07<00:04, 4.21it/s]
64%|██████▍ | 32/50 [00:07<00:04, 4.21it/s]
66%|██████▌ | 33/50 [00:07<00:04, 4.21it/s]
68%|██████▊ | 34/50 [00:07<00:03, 4.21it/s]
70%|███████ | 35/50 [00:08<00:03, 4.21it/s]
72%|███████▏ | 36/50 [00:08<00:03, 4.21it/s]
74%|███████▍ | 37/50 [00:08<00:03, 4.20it/s]
76%|███████▌ | 38/50 [00:08<00:02, 4.19it/s]
78%|███████▊ | 39/50 [00:08<00:02, 4.19it/s]
80%|████████ | 40/50 [00:09<00:02, 4.18it/s]
82%|████████▏ | 41/50 [00:09<00:02, 4.18it/s]
84%|████████▍ | 42/50 [00:09<00:01, 4.18it/s]
86%|████████▌ | 43/50 [00:09<00:01, 4.19it/s]
88%|████████▊ | 44/50 [00:10<00:01, 4.19it/s]
90%|█████████ | 45/50 [00:10<00:01, 4.19it/s]
92%|█████████▏| 46/50 [00:10<00:00, 4.19it/s]
94%|█████████▍| 47/50 [00:10<00:00, 4.19it/s]
96%|█████████▌| 48/50 [00:11<00:00, 4.19it/s]
98%|█████████▊| 49/50 [00:11<00:00, 4.18it/s]
100%|██████████| 50/50 [00:11<00:00, 4.17it/s]
100%|██████████| 50/50 [00:11<00:00, 4.31it/s]
0%| | 0/50 [00:00<?, ?it/s]
2%|▏ | 1/50 [00:00<00:11, 4.21it/s]
4%|▍ | 2/50 [00:00<00:11, 4.19it/s]
6%|▌ | 3/50 [00:00<00:11, 4.19it/s]
8%|▊ | 4/50 [00:00<00:10, 4.19it/s]
10%|█ | 5/50 [00:01<00:10, 4.13it/s]
12%|█▏ | 6/50 [00:01<00:10, 4.15it/s]
14%|█▍ | 7/50 [00:01<00:10, 4.16it/s]
16%|█▌ | 8/50 [00:01<00:10, 4.17it/s]
18%|█▊ | 9/50 [00:02<00:09, 4.16it/s]
20%|██ | 10/50 [00:02<00:09, 4.16it/s]
22%|██▏ | 11/50 [00:02<00:09, 4.16it/s]
24%|██▍ | 12/50 [00:02<00:09, 4.15it/s]
26%|██▌ | 13/50 [00:03<00:08, 4.13it/s]
28%|██▊ | 14/50 [00:03<00:08, 4.13it/s]
30%|███ | 15/50 [00:03<00:08, 4.14it/s]
32%|███▏ | 16/50 [00:03<00:08, 4.15it/s]
34%|███▍ | 17/50 [00:04<00:07, 4.16it/s]
36%|███▌ | 18/50 [00:04<00:07, 4.17it/s]
38%|███▊ | 19/50 [00:04<00:07, 4.17it/s]
40%|████ | 20/50 [00:04<00:07, 4.18it/s]
42%|████▏ | 21/50 [00:05<00:06, 4.19it/s]
44%|████▍ | 22/50 [00:05<00:06, 4.19it/s]
46%|████▌ | 23/50 [00:05<00:06, 4.19it/s]
48%|████▊ | 24/50 [00:05<00:06, 4.19it/s]
50%|█████ | 25/50 [00:05<00:05, 4.18it/s]
52%|█████▏ | 26/50 [00:06<00:05, 4.18it/s]
54%|█████▍ | 27/50 [00:06<00:05, 4.18it/s]
56%|█████▌ | 28/50 [00:06<00:05, 4.18it/s]
58%|█████▊ | 29/50 [00:06<00:05, 4.18it/s]
60%|██████ | 30/50 [00:07<00:04, 4.18it/s]
62%|██████▏ | 31/50 [00:07<00:04, 4.19it/s]
64%|██████▍ | 32/50 [00:07<00:04, 4.18it/s]
66%|██████▌ | 33/50 [00:07<00:04, 4.18it/s]
68%|██████▊ | 34/50 [00:08<00:03, 4.18it/s]
70%|███████ | 35/50 [00:08<00:03, 4.18it/s]
72%|███████▏ | 36/50 [00:08<00:03, 4.17it/s]
74%|███████▍ | 37/50 [00:08<00:03, 4.16it/s]
76%|███████▌ | 38/50 [00:09<00:02, 4.13it/s]
78%|███████▊ | 39/50 [00:09<00:02, 4.12it/s]
80%|████████ | 40/50 [00:09<00:02, 4.13it/s]
82%|████████▏ | 41/50 [00:09<00:02, 4.14it/s]
84%|████████▍ | 42/50 [00:10<00:01, 4.15it/s]
86%|████████▌ | 43/50 [00:10<00:01, 4.15it/s]
88%|████████▊ | 44/50 [00:10<00:01, 4.16it/s]
90%|█████████ | 45/50 [00:10<00:01, 4.17it/s]
92%|█████████▏| 46/50 [00:11<00:00, 4.18it/s]
94%|█████████▍| 47/50 [00:11<00:00, 4.19it/s]
96%|█████████▌| 48/50 [00:11<00:00, 4.19it/s]
98%|█████████▊| 49/50 [00:11<00:00, 4.19it/s]
100%|██████████| 50/50 [00:11<00:00, 4.18it/s]
100%|██████████| 50/50 [00:11<00:00, 4.17it/s]
0%| | 0/35 [00:00<?, ?it/s]
11%|█▏ | 4/35 [00:00<00:00, 35.70it/s]
23%|██▎ | 8/35 [00:00<00:00, 35.83it/s]
34%|███▍ | 12/35 [00:00<00:00, 35.97it/s]
46%|████▌ | 16/35 [00:00<00:00, 36.04it/s]
57%|█████▋ | 20/35 [00:00<00:00, 36.02it/s]
69%|██████▊ | 24/35 [00:00<00:00, 36.12it/s]
80%|████████ | 28/35 [00:00<00:00, 36.18it/s]
91%|█████████▏| 32/35 [00:00<00:00, 36.16it/s]
100%|██████████| 35/35 [00:00<00:00, 36.10it/s]
0it [00:00, ?it/s]
12it [00:00, 181.31it/s]
0%| | 0/7000 [00:00<?, ?it/s]
42%|████▏ | 2940/7000 [00:00<00:00, 29386.44it/s]
84%|████████▍ | 5880/7000 [00:00<00:00, 29391.71it/s]
100%|██████████| 7000/7000 [00:00<00:00, 29406.50it/s]
Display relevant plots#
Let’s display some of the plots generated during the pipeline.
debug_folder = Path("debug")
debug_images = sorted(debug_folder.glob("*.png"))
def get_image_path(name):
return [img_path for img_path in debug_images if name in img_path.name][0]
def show_image(path):
img = plt.imread(path)
plt.imshow(img)
plt.axis("off")
plt.show()
The synthetic image with two cells that was generated
show_image(get_image_path("image_"))

Rotation angles for incremental pipeline and sinusoidal pattern
show_image(get_image_path("rotation_angles"))

Fit an ellipse to the largest blob for different angle positions

Estimated center of rotation: (63, 77)
Estimated rotation plane angle: 12.2
Estimated rotation plane orientation: -33.3
Derotated movie with the sinusoidal angle pattern using the information found in the previous step
show_image(get_image_path("derotated_sinusoidal"))

Plot mean projection of the derotated movie as a check of the derotation quality
show_image(get_image_path("mean_projection"))

Total running time of the script: (0 minutes 35.611 seconds)