Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Find centre of rotation #24

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
168100a
Add empty method
lauraporta Sep 16, 2024
b76a30a
Reorganize methods order
lauraporta Sep 16, 2024
f6adedf
Add working methods to find center of rotation 🎉
lauraporta Sep 19, 2024
174fd9e
Include usage of center of rotation in main pipeline
lauraporta Sep 19, 2024
aae7c67
Fixes debugging plots and logging usage
lauraporta Sep 23, 2024
9bf17eb
Add plotting hooks and further params to main derotate by line function
lauraporta Sep 25, 2024
6000609
Improve debug plots
lauraporta Sep 25, 2024
a0c6017
WIP 🏗️: draft pipeline for adapting center of rotation
lauraporta Sep 25, 2024
29e9d27
Add basic rotator and a simple usage of it
lauraporta Sep 25, 2024
dfe659a
Add docstrings
lauraporta Sep 25, 2024
c913a06
Add basic tests
lauraporta Sep 25, 2024
4832672
Make function name consistent
lauraporta Sep 26, 2024
55b080e
Fix Rotator and join it with the derotator in an example
lauraporta Sep 26, 2024
c3cf60e
Add tests
lauraporta Sep 26, 2024
c825a82
Delete duplicate file
lauraporta Sep 26, 2024
35a0b7f
Merge commit 'c825a828116dd382d8e9f8e1695c46adcdb94ecc' into feature/…
lauraporta Sep 26, 2024
e5cac06
Update basic rotator to include different center of rotation
lauraporta Sep 26, 2024
860a2fa
WIP: changing the main derotation by line algorithm
lauraporta Sep 26, 2024
1412348
Resolve naming (in many cases with "rotation" I meant derotation)
lauraporta Sep 26, 2024
c0423a0
Remove linear interpolation and recompute test images - now it's a sq…
lauraporta Sep 27, 2024
765c4de
Update tests rotator with different center
lauraporta Sep 27, 2024
df141be
Update tests with new derotation version
lauraporta Sep 27, 2024
0721e5d
Add new generated derotated squares: faster derotation by line leads …
lauraporta Sep 27, 2024
c4f9d14
Add test for derotation with different centre
lauraporta Sep 27, 2024
edee980
Add wrongly deleted hook
lauraporta Sep 27, 2024
2779819
Clean up and refactor the main pipeline around the center of rotation…
lauraporta Sep 27, 2024
bfa4443
Remove hooks from pipeline
lauraporta Sep 30, 2024
0dd3c6d
Change variable names in plotting hooks
lauraporta Sep 30, 2024
ca6cc03
Plotting bug fixed
lauraporta Sep 30, 2024
fde0592
Fix angle indices bug in Rotator
lauraporta Sep 30, 2024
d783005
WIP: finding the center of rotation via ellipse fitting
lauraporta Sep 30, 2024
a4dc480
WIP: script to test the integration of the two pipelines to find the …
lauraporta Sep 30, 2024
8963f5f
Comment one hook
lauraporta Sep 30, 2024
52be41c
Use blank pixel
lauraporta Sep 30, 2024
3d5c1ce
Use the script to test with a different center of rotation, works whe…
lauraporta Sep 30, 2024
48c8b54
Add another debugging plot
lauraporta Sep 30, 2024
dddbaf3
Reorganize examples
lauraporta Oct 3, 2024
d69ec18
Uncomment part of plotting hooks
lauraporta Oct 3, 2024
7a00c37
Fix pytest error (missing required property)
lauraporta Oct 3, 2024
a211832
Move the plots out of the main function in integration script
lauraporta Oct 3, 2024
10ec8e8
Move logic to get the largest blob in a separate method
lauraporta Oct 3, 2024
ef186f9
Add integration tests on the integration of the two pipelines to find…
lauraporta Oct 3, 2024
1f8ded8
Don't need to save plots in tests
lauraporta Oct 3, 2024
a941f41
Also do't need the folder
lauraporta Oct 3, 2024
e45ff2c
Let's accept little differences in the derotation
lauraporta Oct 3, 2024
81a72c8
Increase the tolerance and improve error message
lauraporta Oct 3, 2024
0737e65
Update workflows and add dependabot yml
lauraporta Oct 3, 2024
ff55b72
WIP docs
lauraporta Oct 3, 2024
aa37d4e
Fix mypy error messages
lauraporta Oct 4, 2024
3f631bf
Move the plots of the integration script into the integration test
lauraporta Oct 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"
20 changes: 16 additions & 4 deletions .github/workflows/docs_build_and_deploy.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build Sphinx docs and deploy to GitHub Pages
name: Docs

# Generate the documentation on all merges to main, all pull requests, or by
# manual workflow dispatch. The build job can be used as a CI check that the
Expand All @@ -12,23 +12,35 @@ on:
tags:
- '*'
pull_request:
merge_group:
workflow_dispatch:

jobs:
linting:
# scheduled workflows should not run on forks
if: (${{ github.event_name == 'schedule' }} && ${{ github.repository_owner == 'neuroinformatics-unit' }} && ${{ github.ref == 'refs/heads/main' }}) || (${{ github.event_name != 'schedule' }})
runs-on: ubuntu-latest
steps:
- uses: neuroinformatics-unit/actions/lint@v2

build_sphinx_docs:
name: Build Sphinx Docs
runs-on: ubuntu-latest
steps:
- uses: neuroinformatics-unit/actions/build_sphinx_docs@v2
- uses: neuroinformatics-unit/actions/build_sphinx_docs@main
with:
python-version: 3.11
use-make: true

deploy_sphinx_docs:
name: Deploy Sphinx Docs
needs: build_sphinx_docs
permissions:
contents: write
if: github.event_name == 'push' && github.ref_type == 'tag'
if: (github.event_name == 'push' && github.ref_type == 'tag') || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: neuroinformatics-unit/actions/deploy_sphinx_docs@v2
- uses: neuroinformatics-unit/actions/deploy_sphinx_docs@main
with:
secret_input: ${{ secrets.GITHUB_TOKEN }}
use-make: true
12 changes: 8 additions & 4 deletions .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
tags:
- '*'
pull_request:
merge_group:

jobs:
linting:
Expand All @@ -27,20 +28,23 @@ jobs:
strategy:
matrix:
# Run all supported Python versions on linux
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.10", "3.11", "3.12"]
os: [ubuntu-latest]
# Include one windows and macos run
# Include 1 Intel macos (13) and 1 M1 macos (latest) and 1 Windows run
include:
- os: macos-13
python-version: "3.11"
- os: macos-latest
python-version: "3.10"
python-version: "3.11"
- os: windows-latest
python-version: "3.10"
python-version: "3.11"

steps:
# Run tests
- uses: neuroinformatics-unit/actions/test@v2
with:
python-version: ${{ matrix.python-version }}
secret-codecov-token: ${{ secrets.CODECOV_TOKEN }}

build_sdist_wheels:
name: Build source distribution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from sklearn.mixture import GaussianMixture
from tifffile import imsave

from derotation.derotate_by_line import rotate_an_image_array_line_by_line
from derotation.derotate_by_line import derotate_an_image_array_line_by_line
from derotation.load_data.custom_data_loaders import (
get_analog_signals,
read_randomized_stim_table,
Expand Down Expand Up @@ -56,7 +56,7 @@
- saving the masked image stack
"""
self.process_analog_signals()
rotated_images = self.rotate_frames_line_by_line()
rotated_images = self.derotate_frames_line_by_line()

Check warning on line 59 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L59

Added line #L59 was not covered by tests
masked = self.add_circle_mask(rotated_images, self.mask_diameter)
self.save(masked)
self.save_csv_with_derotation_data()
Expand Down Expand Up @@ -168,14 +168,20 @@
self.debugging_plots = self.config["debugging_plots"]

if self.debugging_plots:
self.debug_plots_folder = self.config["paths_write"][
"debug_plots_folder"
]
self.debug_plots_folder = Path(

Check warning on line 171 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L171

Added line #L171 was not covered by tests
self.config["paths_write"]["debug_plots_folder"]
)
Path(self.debug_plots_folder).mkdir(parents=True, exist_ok=True)

logging.info(f"Dataset {self.filename_raw} loaded")
logging.info(f"Filename: {self.filename}")

self.center_of_rotation = (

Check warning on line 179 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L179

Added line #L179 was not covered by tests
self.num_lines_per_frame // 2,
self.num_lines_per_frame // 2,
)
self.hooks = {}

Check warning on line 183 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L183

Added line #L183 was not covered by tests

### ----------------- Analog signals processing pipeline ------------- ###
def process_analog_signals(self):
"""From the analog signals (frame clock, line clock, full rotation,
Expand Down Expand Up @@ -790,26 +796,39 @@
plt.savefig(self.debug_plots_folder / "rotation_angles.png")

### ----------------- Derotation ----------------- ###
def rotate_frames_line_by_line(self) -> np.ndarray:
"""Rotates the image stack line by line, using the rotation angles
by line calculated from the analog signals.

Description of the algorithm:
- takes one line from the image stack
- creates a new image with only that line
- rotates the line by the given angle
- substitutes the line in the new image
- adds the new image to the rotated image stack

Edge cases and how they are handled:
- the rotation starts in the middle of the image -> the previous lines
are copied from the first frame
- the rotation ends in the middle of the image -> the remaining lines
are copied from the last frame

Before derotation, it finds the image offset, which is the peak of
the gaussian mixture model fitted to the image histogram. It is
useful to fill in the blank pixels that appear during the derotation.

def plot_max_projection_with_center(self):
"""Plots the maximum projection of the image stack with the center
of rotation.
This plot will be saved in the debug_plots folder.
Please inspect it to check that the center of rotation is correctly
placed.
"""
logging.info("Plotting max projection with center...")

Check warning on line 807 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L807

Added line #L807 was not covered by tests

max_projection = np.max(self.image_stack, axis=0)

Check warning on line 809 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L809

Added line #L809 was not covered by tests

fig, ax = plt.subplots(1, 1, figsize=(5, 5))

Check warning on line 811 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L811

Added line #L811 was not covered by tests

ax.imshow(max_projection, cmap="gray")
ax.scatter(

Check warning on line 814 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L813-L814

Added lines #L813 - L814 were not covered by tests
self.center_of_rotation[0],
self.center_of_rotation[1],
color="red",
marker="x",
)

ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

Check warning on line 822 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L821-L822

Added lines #L821 - L822 were not covered by tests

ax.axis("off")

Check warning on line 824 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L824

Added line #L824 was not covered by tests

plt.savefig(self.debug_plots_folder / "max_projection_with_center.png")

Check warning on line 826 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L826

Added line #L826 was not covered by tests

def derotate_frames_line_by_line(self) -> np.ndarray:
"""Wrapper for the function `derotate_an_image_array_line_by_line`.
Before calling the function, it finds the F0 image offset with
`find_image_offset`.

Returns
-------
Expand All @@ -818,12 +837,22 @@
"""
logging.info("Starting derotation by line...")

if self.debugging_plots:
self.plot_max_projection_with_center()

Check warning on line 841 in derotation/analysis/full_derotation_pipeline.py

View check run for this annotation

Codecov / codecov/patch

derotation/analysis/full_derotation_pipeline.py#L841

Added line #L841 was not covered by tests

offset = self.find_image_offset(self.image_stack[0])

rotated_image_stack = rotate_an_image_array_line_by_line(
rotated_image_stack = derotate_an_image_array_line_by_line(
self.image_stack,
self.rot_deg_line,
blank_pixels_value=offset,
center=self.center_of_rotation,
plotting_hook_line_addition=self.hooks.get(
"plotting_hook_line_addition"
),
plotting_hook_image_completed=self.hooks.get(
"plotting_hook_image_completed"
),
)

logging.info("✨ Image stack rotated ✨")
Expand Down
Loading