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

Background Components for Caiman #783

Merged
merged 33 commits into from
May 3, 2024
Merged
Changes from 4 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
98d984c
added placeholder background functions
pauladkisson Mar 18, 2024
e9f15ef
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 18, 2024
b23f64d
added first pass of background plane segmentation
pauladkisson Mar 28, 2024
a690ade
added default handling of background_plane_segmentation_name
pauladkisson Mar 28, 2024
ff1528a
added background to fluorescence traces
pauladkisson Mar 28, 2024
fa2f0d7
added parametrized conversion_options to caiman data tests
pauladkisson Mar 29, 2024
6bd1533
refactored background plane segmentation to a separate function
pauladkisson Mar 29, 2024
b489bf0
refactored add_segmentations fns to use a common private method
pauladkisson Mar 29, 2024
e17cc53
refactored add_fluorescence_traces fns to use a common private method
pauladkisson Mar 29, 2024
71ee98e
reparametrized caiman tests
pauladkisson Mar 29, 2024
1056a80
Merge branch 'main' into caiman
pauladkisson Mar 29, 2024
ac9e146
Merge branch 'main' into caiman
pauladkisson Apr 1, 2024
893de17
pinned caiman PR version of roiextractors
pauladkisson Apr 2, 2024
d875d4c
made background optional for other extractors
pauladkisson Apr 2, 2024
53ce8cb
Merge branch 'main' into caiman
pauladkisson Apr 2, 2024
df7e1bd
updated changelog
pauladkisson Apr 2, 2024
1490938
updated requirements
pauladkisson Apr 2, 2024
45fd891
fixed neuropil name bug
pauladkisson Apr 3, 2024
193f679
added test for invalid mask type
pauladkisson Apr 3, 2024
c6f8f3b
Merge branch 'main' into caiman
pauladkisson Apr 3, 2024
fd9020e
moved test for invalid mask type to unit test section
pauladkisson Apr 3, 2024
ad35e41
moved test for invalid mask type to unit test section
pauladkisson Apr 3, 2024
ddb8a30
removed neuropil unit tests from non-background methods
pauladkisson Apr 3, 2024
39f45bc
added neuropil traces to fluorescence unless include_background_segme…
pauladkisson Apr 3, 2024
dc62982
include_background --> include_background_segmentation in tests
pauladkisson Apr 4, 2024
734765f
added extra check for assertionerror
pauladkisson Apr 4, 2024
b71e2b5
Merge branch 'main' into caiman
CodyCBakerPhD Apr 8, 2024
43e91ee
Merge branch 'main' into caiman
pauladkisson Apr 9, 2024
05128cd
Update requirements.txt
pauladkisson Apr 9, 2024
979b076
Merge branch 'main' into caiman
pauladkisson Apr 11, 2024
a0e2ee6
Merge branch 'main' into caiman
CodyCBakerPhD Apr 16, 2024
4db7a48
Merge branch 'main' into caiman
pauladkisson May 3, 2024
bbae94f
comment problematic test
pauladkisson May 3, 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
88 changes: 87 additions & 1 deletion src/neuroconv/tools/roiextractors/roiextractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,26 @@ def get_default_segmentation_metadata() -> DeepDict:
name="PlaneSegmentation",
description="Segmented ROIs",
imaging_plane=metadata["Ophys"]["ImagingPlane"][0]["name"],
)
),
dict(
name="BackgroundPlaneSegmentation",
description="Segmented Background Components",
imaging_plane=metadata["Ophys"]["ImagingPlane"][0]["name"],
),
],
)

# default_background_image_segmentation = dict(
# name="BackgroundImageSegmentation",
# plane_segmentations=[
# dict(
# name="BackgroundPlaneSegmentation",
# description="Segmented Background Components",
# imaging_plane=metadata["Ophys"]["ImagingPlane"][0]["name"],
# )
# ],
# )

default_segmentation_images = dict(
name="SegmentationImages",
description="The summary images of the segmentation.",
Expand All @@ -126,6 +142,7 @@ def get_default_segmentation_metadata() -> DeepDict:
Fluorescence=default_fluorescence,
DfOverF=default_df_over_f,
ImageSegmentation=default_image_segmentation,
# BackgroundImageSegmentation=default_background_image_segmentation,
SegmentationImages=default_segmentation_images,
),
)
Expand Down Expand Up @@ -681,6 +698,7 @@ def add_plane_segmentation(
metadata: Optional[dict],
plane_segmentation_name: Optional[str] = None,
plane_segmentation_index: Optional[int] = None, # TODO: to be removed
background_plane_segmentation_name: Optional[str] = None,
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
include_roi_centroids: bool = True,
include_roi_acceptance: bool = True,
mask_type: Optional[str] = "image", # Optional[Literal["image", "pixel"]]
Expand Down Expand Up @@ -766,6 +784,20 @@ def add_plane_segmentation(
f"Metadata for Plane Segmentation '{plane_segmentation_name}' not found in metadata['Ophys']['ImageSegmentation']['plane_segmentations']."
)

background_plane_segmentation_name = (
background_plane_segmentation_name
or default_metadata["Ophys"]["ImageSegmentation"]["plane_segmentations"][1]["name"]
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
)
background_plane_segmentation_metadata = None
for meta in metadata_copy["Ophys"]["ImageSegmentation"]["plane_segmentations"]:
if meta["name"] == background_plane_segmentation_name:
background_plane_segmentation_metadata = meta
break
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
if background_plane_segmentation_metadata is None:
raise ValueError(
f"Metadata for Plane Segmentation '{background_plane_segmentation_name}' not found in metadata['Ophys']['ImageSegmentation']['plane_segmentations']."
)

imaging_plane_name = plane_segmentation_metadata["imaging_plane"]
add_imaging_plane(nwbfile=nwbfile, metadata=metadata_copy, imaging_plane_name=imaging_plane_name)
add_image_segmentation(nwbfile=nwbfile, metadata=metadata_copy)
Expand All @@ -777,6 +809,7 @@ def add_plane_segmentation(
# Check if the plane segmentation already exists in the image segmentation
if plane_segmentation_name not in image_segmentation.plane_segmentations:
roi_ids = segmentation_extractor.get_roi_ids()
background_ids = segmentation_extractor.get_background_ids()

if include_roi_acceptance:
accepted_ids = [int(roi_id in segmentation_extractor.get_accepted_list()) for roi_id in roi_ids]
Expand All @@ -785,15 +818,24 @@ def add_plane_segmentation(
imaging_plane = nwbfile.imaging_planes[imaging_plane_name]
plane_segmentation_kwargs = deepcopy(plane_segmentation_metadata)
plane_segmentation_kwargs.update(imaging_plane=imaging_plane)
background_plane_segmentation_kwargs = deepcopy(background_plane_segmentation_metadata)
background_plane_segmentation_kwargs.update(imaging_plane=imaging_plane)
if mask_type is None:
plane_segmentation = PlaneSegmentation(id=roi_ids, **plane_segmentation_kwargs)
background_plane_segmentation = PlaneSegmentation(id=background_ids, **background_plane_segmentation_kwargs)
elif mask_type == "image":
plane_segmentation = PlaneSegmentation(id=roi_ids, **plane_segmentation_kwargs)
plane_segmentation.add_column(
name="image_mask",
description="Image masks for each ROI.",
data=H5DataIO(segmentation_extractor.get_roi_image_masks().T, **compression_options),
)
background_plane_segmentation = PlaneSegmentation(id=background_ids, **background_plane_segmentation_kwargs)
background_plane_segmentation.add_column(
name="image_mask",
description="Image masks for each background ROI.",
data=H5DataIO(segmentation_extractor.get_background_image_masks().T, **compression_options),
)
elif mask_type == "pixel" or mask_type == "voxel":
pixel_masks = segmentation_extractor.get_roi_pixel_masks()
num_pixel_dims = pixel_masks[0].shape[1]
Expand Down Expand Up @@ -821,6 +863,35 @@ def add_plane_segmentation(
for roi_id, pixel_mask in zip(roi_ids, pixel_masks):
plane_segmentation.add_roi(**{"id": roi_id, mask_type_kwarg: [tuple(x) for x in pixel_mask]})

# TODO: Make sure pixel masks are tested properly
background_pixel_masks = segmentation_extractor.get_background_pixel_masks()
num_pixel_dims = background_pixel_masks[0].shape[1]

assert num_pixel_dims in [3, 4], (
"The segmentation extractor returned a pixel mask that is not 3- or 4- dimensional! "
"Please open a ticket with https://github.com/catalystneuro/roiextractors/issues"
)
if mask_type == "pixel" and num_pixel_dims == 4:
warn(
"Specified mask_type='pixel', but ROIExtractors returned 4-dimensional masks. "
"Using mask_type='voxel' instead."
)
mask_type = "voxel"
if mask_type == "voxel" and num_pixel_dims == 3:
warn(
"Specified mask_type='voxel', but ROIExtractors returned 3-dimensional masks. "
"Using mask_type='pixel' instead."
)
mask_type = "pixel"

mask_type_kwarg = f"{mask_type}_mask"
background_plane_segmentation = PlaneSegmentation(**background_plane_segmentation_kwargs)

for background_id, background_pixel_mask in zip(background_ids, background_pixel_masks):
background_plane_segmentation.add_roi(
**{"id": background_id, mask_type_kwarg: [tuple(x) for x in background_pixel_mask]}
)

if include_roi_centroids:
# ROIExtractors uses height x width x (depth), but NWB uses width x height x depth
tranpose_image_convention = (1, 0) if len(segmentation_extractor.get_image_size()) == 2 else (1, 0, 2)
Expand All @@ -844,9 +915,14 @@ def add_plane_segmentation(
)

image_segmentation.add_plane_segmentation(plane_segmentations=[plane_segmentation])
image_segmentation.add_plane_segmentation(plane_segmentations=[background_plane_segmentation])
return nwbfile


def add_background_plane_segmentation():
pauladkisson marked this conversation as resolved.
Show resolved Hide resolved
pass


def add_fluorescence_traces(
segmentation_extractor: SegmentationExtractor,
nwbfile: NWBFile,
Expand Down Expand Up @@ -996,6 +1072,7 @@ def _create_roi_table_region(
nwbfile: NWBFile,
metadata: dict,
plane_segmentation_name: Optional[str] = None,
background_plane_segmentation_name: Optional[str] = None,
plane_index: Optional[int] = None,
):
"""Private method to create ROI table region.
Expand Down Expand Up @@ -1024,6 +1101,7 @@ def _create_roi_table_region(
nwbfile=nwbfile,
metadata=metadata,
plane_segmentation_name=plane_segmentation_name,
background_plane_segmentation_name=background_plane_segmentation_name,
)

image_segmentation_name = image_segmentation_metadata["name"]
Expand Down Expand Up @@ -1064,6 +1142,10 @@ def _get_segmentation_data_interface(nwbfile: NWBFile, data_interface_name: str)
return data_interface


def add_background_fluorescence_traces():
pass


def add_summary_images(
nwbfile: NWBFile,
segmentation_extractor: SegmentationExtractor,
Expand Down Expand Up @@ -1146,6 +1228,7 @@ def add_segmentation(
nwbfile: NWBFile,
metadata: Optional[dict] = None,
plane_segmentation_name: Optional[str] = None,
background_plane_segmentation_name: Optional[str] = None,
plane_num: Optional[int] = None, # TODO: to be removed
include_roi_centroids: bool = True,
include_roi_acceptance: bool = True,
Expand All @@ -1163,12 +1246,14 @@ def add_segmentation(
nwbfile=nwbfile,
metadata=metadata,
plane_segmentation_name=plane_segmentation_name,
background_plane_segmentation_name=background_plane_segmentation_name,
include_roi_centroids=include_roi_centroids,
include_roi_acceptance=include_roi_acceptance,
mask_type=mask_type,
iterator_options=iterator_options,
compression_options=compression_options,
)
# add_background_plane_segmentation()

# Add fluorescence traces:
add_fluorescence_traces(
Expand All @@ -1179,6 +1264,7 @@ def add_segmentation(
iterator_options=iterator_options,
compression_options=compression_options,
)
add_background_fluorescence_traces()

# Adding summary images (mean and correlation)
add_summary_images(
Expand Down
Loading