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

ezSegmentation #958

Merged
merged 123 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 122 commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
fecfd9a
added started ez_seg file + test
srivarra Mar 23, 2023
3918639
Merge branch 'main' into ezSegmenter/start
srivarra Mar 23, 2023
ed05bc6
applied filters.threshold_local's output to create a binary mask
srivarra Mar 23, 2023
3a9ff7f
Merge branch 'main' into ezSegmenter/start
srivarra Mar 23, 2023
5c8547b
Merge branch 'main' into ezSegmenter/start
srivarra Mar 24, 2023
e9a139a
Adding merge_mask functionality to be later built into merge_masks no…
bryjcannon Apr 13, 2023
ec9c9ef
Merge branch 'main' into ezSegmenter/start
srivarra Apr 17, 2023
5554500
added composite builder functionality - ready for refactoring
bryjcannon Apr 19, 2023
671ca03
merging updated branch locally
bryjcannon Apr 19, 2023
9db842d
Merge branch 'main' into ezSegmenter/start
srivarra May 15, 2023
4ad52bc
Merge branch 'main' into ezSegmenter/start
srivarra May 17, 2023
6c372bb
ezseg_v1 notebook
srivarra May 22, 2023
96381c7
Merge branch 'main' into ezSegmenter/start
srivarra May 22, 2023
8a813ba
Merge branch 'main' into ezSegmenter/start
srivarra Jun 27, 2023
b8db373
Second version of ez notebook started, changes to composite builder a…
bryjcannon Jul 5, 2023
91eff3b
Merge branch 'main' into ezSegmenter/start
srivarra Jul 6, 2023
9360cfd
Added a relabeleing step necessary for masks merging. Need to test it…
bryjcannon Jul 13, 2023
0af84b7
merging remote with local
bryjcannon Jul 13, 2023
ba924d3
Merge branch 'main' into ezSegmenter/start
srivarra Jul 19, 2023
8c1fa1e
refactor stage 1
srivarra Jul 20, 2023
6fb702d
Merge branch 'main' into ezSegmenter/start
srivarra Jul 20, 2023
6874f1b
Merge branch 'main' into ezSegmenter/start
srivarra Jul 21, 2023
f0ed549
refactoring pt.2
srivarra Jul 20, 2023
a851811
refactor pt. 3
srivarra Jul 25, 2023
d358437
Merge branch 'main' into ezSegmenter/start
srivarra Jul 25, 2023
7051dd6
added ez_seg folder in tests
srivarra Jul 25, 2023
5cd412f
switch order of composite builder & mask creator, added mask_name to …
bryjcannon Aug 1, 2023
602be97
notebook adjustments
srivarra Jul 26, 2023
e12ba58
notebook adjustments v3
srivarra Jul 26, 2023
fb809af
Merge branch 'main' into ezSegmenter/start
srivarra Aug 10, 2023
abe5e34
modified: templates/ez_testing/ezseg_v2.ipynb
srivarra Aug 10, 2023
614b076
Merge branch 'main' into ezSegmenter/start
srivarra Aug 10, 2023
76e37ee
refactor sections 1-3
srivarra Aug 11, 2023
a2be8f0
removed unused import
srivarra Aug 11, 2023
03054ff
renumber mask adjustments
srivarra Aug 11, 2023
a6e780f
Switched ordering of mask merge and mask relabeling. Additionally upd…
bryjcannon Sep 19, 2023
cfde795
Renamed the dir input to cell table creation as root_mask_dir to acco…
bryjcannon Sep 19, 2023
55bbf5e
Composite builder now iterates over all input fov's. Bug fixed where …
bryjcannon Sep 22, 2023
438bb30
Fixed problem with ez segmentation mask maker not performing size exc…
bryjcannon Sep 26, 2023
4ecdb16
Updated visuals for composite, mask overlay. Updated notebook with mu…
bryjcannon Sep 29, 2023
a111517
Updated display code and notebook cells for ez segmentation step.
bryjcannon Oct 4, 2023
b8fb984
Merge branch 'main' into ezSegmenter/start
srivarra Oct 6, 2023
e6461c4
Updated ez segmentation, merging, and mask display functions.
bryjcannon Oct 12, 2023
e449a6d
Merge branch 'ezSegmenter/start' of https://github.com/angelolab/ark-…
bryjcannon Oct 12, 2023
7a0c75e
Fixed relabeline of all masks in merged mask dir.
bryjcannon Oct 12, 2023
a2f0aa7
base mantis project for ezseg data
srivarra Oct 13, 2023
c0afdb2
docs, nb cleanup
srivarra Oct 13, 2023
a771c41
ezseg_utils fix
srivarra Oct 13, 2023
d214bcf
Updated ez object cell table creation in marker_quantification file. …
bryjcannon Oct 17, 2023
182033a
merging changes between mantis and marker_quant updates.
bryjcannon Oct 17, 2023
47dae13
Refactored ez notebook and modules, added log creator.
bryjcannon Oct 18, 2023
7fa2001
cleaned up naming, variable, errors across all ez code.
bryjcannon Oct 18, 2023
f26a3b9
Final code quality changes for v1 publish.
bryjcannon Oct 19, 2023
0ed4402
Changes for merge.
bryjcannon Oct 24, 2023
9aa7626
Code and ouput cleanup.
bryjcannon Oct 24, 2023
73b5e95
Merge branch 'main' into ezSegmenter/start
bryjcannon Oct 25, 2023
9db1b58
More cleanup before merge.
bryjcannon Oct 25, 2023
7ef1b80
Merging from main.
bryjcannon Oct 25, 2023
020b5c1
Removed old templates.
bryjcannon Oct 25, 2023
7c82461
notebook cleanup
bryjcannon Oct 25, 2023
90e18aa
Initial commit of ezSegmenter example dataset integration
alex-l-kong Oct 27, 2023
47a0263
Initial notebook commit
alex-l-kong Oct 27, 2023
aa81b13
Merge remote-tracking branch 'origin/ezSegmenter/start' into ezSegmen…
alex-l-kong Oct 30, 2023
7bfb8a8
Fix CI file to use Python 3.11
alex-l-kong Oct 30, 2023
1dcee96
Skip the create_object_masks test
alex-l-kong Oct 30, 2023
21d0c6d
Remove syntax errors
alex-l-kong Oct 30, 2023
fa694aa
Doc fixes
alex-l-kong Oct 30, 2023
9a74ad4
Type hinting fix
alex-l-kong Oct 30, 2023
8adddae
Add full notebook testing for ez_segmenter notebook
alex-l-kong Oct 30, 2023
8e0feb4
More doc fixes (multiple_mask_displays)
alex-l-kong Oct 30, 2023
0387d77
Update tests for ezSeg example dataset
alex-l-kong Oct 30, 2023
190da32
Officially merge ezSegmenter example dataset in
alex-l-kong Oct 31, 2023
854709b
Merge branch 'main' into ezSegmenter/start
alex-l-kong Oct 31, 2023
8a17771
Ensure easier naming of files by specifying additional path to ezSegm…
alex-l-kong Oct 31, 2023
76c8946
Changed example data dir structure.
bryjcannon Nov 1, 2023
b2d60fc
Clean up path specification for example dataset ez_seg data download
alex-l-kong Nov 6, 2023
10d4faa
Account for new 'mask_type' column that gets generated in the cell table
alex-l-kong Nov 6, 2023
95ee41a
Fix marker_quantification tests
alex-l-kong Nov 6, 2023
efef9ef
Begin adding tests for ez_seg_utils.py
alex-l-kong Nov 8, 2023
4f1ff08
Add all tests except for split_csvs_by_mask
alex-l-kong Nov 9, 2023
ac93f0b
Added image directory subfolder capability to composites, ez_obj_seg,…
bryjcannon Nov 9, 2023
cefde75
CSV filter testing fleshed out
alex-l-kong Nov 9, 2023
8e40a09
Make sure csv_substr_replace arg gets updated in notebook too
alex-l-kong Nov 9, 2023
18cf45b
Merge remote-tracking branch 'origin/ezSegmenter/start' into ezSegmen…
alex-l-kong Nov 9, 2023
8034a5d
Doc fixes
alex-l-kong Nov 9, 2023
b320c0e
Updated display functions with subfolder access.
bryjcannon Nov 9, 2023
7608016
Merge branch 'ezSegmenter/start' of https://github.com/angelolab/ark-…
bryjcannon Nov 9, 2023
1ede23d
tests mostly finalized
srivarra Nov 9, 2023
bacf449
Remove old start_jupyter.sh notebook
alex-l-kong Nov 9, 2023
3db2b14
merge latest
srivarra Nov 9, 2023
5079e54
Merge branch 'ezSegmenter/start' of github.com:angelolab/ark-analysis…
srivarra Nov 9, 2023
78156ac
notebook tests, try CI
srivarra Nov 9, 2023
e127872
reran ez_seg nb
srivarra Nov 9, 2023
8bea699
replace A | B with Union[A,B]
srivarra Nov 10, 2023
a5c84ed
missed an Optional
srivarra Nov 10, 2023
0595308
as_posix -> as_uri, TestClusterMaskData fix
srivarra Nov 10, 2023
1a5d638
removed a platform specific assert
srivarra Nov 10, 2023
862aac9
removed assert for fov_mapping
srivarra Nov 10, 2023
55c5bbc
Fixed thresholding issue in seg, fixed csv sepeartion in utils.
bryjcannon Nov 13, 2023
0b1e61c
Merging remote and local
bryjcannon Nov 13, 2023
468700b
Ensure that if the csv file doesn't contain csv_to_replace, fix it
alex-l-kong Nov 13, 2023
461238d
Merge remote-tracking branch 'origin/ezSegmenter/start' into ezSegmen…
alex-l-kong Nov 13, 2023
767e749
Fix nbviewer notebook error.
bryjcannon Nov 13, 2023
0f35953
Added readme information, fixed jupyter json error.
bryjcannon Nov 13, 2023
42eee93
-1 -> 'auto' for clarity, rounded and set dtype to int after gaussian…
srivarra Nov 17, 2023
52942d4
Fixed subdirectory issue when using a composite image.
bryjcannon Nov 20, 2023
54fee7c
Add testing for merge masks
alex-l-kong Nov 20, 2023
e573594
Merge remote-tracking branch 'origin/ezSegmenter/start' into ezSegmen…
alex-l-kong Nov 20, 2023
31299f0
Add full testing for composites.py
alex-l-kong Nov 21, 2023
c2d3755
Remove print statements from composites.py
alex-l-kong Nov 21, 2023
8676912
Ensure fixtures get reset for each test
alex-l-kong Nov 21, 2023
9b7fa30
Fixed segmentation issue due to a round error, updated displays, adde…
bryjcannon Nov 27, 2023
cf0be77
Add testing for find_and_copy_files
alex-l-kong Nov 27, 2023
7915151
Add missing notebook tags back and reformat notebook tests to preserv…
alex-l-kong Nov 27, 2023
62dd7cc
Fixed a recursive file copy issue.
bryjcannon Nov 28, 2023
19eef50
Merge branch 'ezSegmenter/start' of https://github.com/angelolab/ark-…
alex-l-kong Nov 28, 2023
1464d6a
Fix check for file to root
alex-l-kong Nov 28, 2023
e545536
Coerce Path types to str for find_and_copy_files
alex-l-kong Nov 28, 2023
0fa9935
Add new composite types to example_dataset_test
alex-l-kong Nov 28, 2023
d4e0a7d
Update type annotation of find_and_copy_files to pathlib.Path, not Li…
alex-l-kong Nov 28, 2023
dc51887
Remove extraneous composite names
alex-l-kong Nov 28, 2023
9334ca9
Update file names in new ezSegmenter example dataset
alex-l-kong Nov 28, 2023
3c6d561
Formatting fix
alex-l-kong Nov 29, 2023
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ We have recorded workshop talks which complement the repository. [MIBI Workshop
#### 1. Segmentation
The [**segmentation notebook**](./templates/1_Segment_Image_Data.ipynb) will walk you through the process of using [Mesmer](https://www.nature.com/articles/s41587-021-01094-0) to segment your image data. This includes selecting the appropriate channel(s) for segmentation, running your data through the network, and then extracting single-cell statistics from the resulting segmentation mask. [Workshop Talk - Session V - Part 1: Segmentation](https://youtu.be/4_AJxrxPYlk?t=231)
- *Note:* It is assumed that the cell table uses the default column names as in `ark/settings.py`. Refer to the [docs](docs/_rtd/data_types.md) to get descriptions of the cell table columns, and methods to adjust them if necessary.
- If you plan to segment out non-traditional cellular structures such as protein aggregates or cytoplasmic projections often found in brain cells (e.g. microglia, astrocytes, and neuropil), try out the companion notebook [**ezSegmenter**](./templates/ez_segmenter.ipynb) either as a stand-alone or in combination with the above standard cell segmentation process.

#### 2. Pixel clustering with Pixie
The first step in the [Pixie](https://doi.org/10.1038/s41467-023-40068-5) pipeline is to run the [**pixel clustering notebook**](./templates/2_Pixie_Cluster_Pixels.ipynb). The notebook walks you through the process of generating pixel clusters for your data, and lets you specify what markers to use for the clustering, train a model, use it to classify your entire dataset, and generate pixel cluster overlays. The notebook includes a GUI for manual cluster adjustment and annotation. [Workshop Talk - Session IV - Pixel Level Analysis](https://youtu.be/e7C1NvaPLaY)
Expand Down
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def dataset_cache_dir() -> Iterator[Union[str, None]]:
yield cache_dir


@pytest.fixture(scope="module")
@pytest.fixture(scope="session")
def rng() -> Generator[np.random.Generator, None, None]:
"""
Create a new Random Number Generator for tests which require randomized data.
Expand Down
10 changes: 10 additions & 0 deletions src/ark/segmentation/ez_seg/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from . import composites, merge_masks, ez_seg_display, ez_seg_utils
from .ez_object_segmentation import create_object_masks

__all__ = [
"composites",
"merge_masks",
"ez_seg_display",
"ez_seg_utils",
"create_object_masks",
]
177 changes: 177 additions & 0 deletions src/ark/segmentation/ez_seg/composites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import pathlib
from typing import List, Union
import numpy as np
import xarray as xr
from alpineer import misc_utils, image_utils, load_utils
from ark.segmentation.ez_seg.ez_seg_utils import log_creator


def composite_builder(
image_data_dir: Union[str, pathlib.Path],
img_sub_folder: str,
fov_list: list[str],
images_to_add: list[str],
images_to_subtract: list[str],
image_type: str,
composite_method: str,
composite_directory: Union[str, pathlib.Path],
composite_name: str,
log_dir: Union[str, pathlib.Path],
) -> None:
"""
Adds tiffs together, either pixel clusters or base signal tiffs and returns a composite channel or mask.

Args:
image_data_dir (Union[str, pathlib.Path]): The path to dir containing the set of all images
which get filtered out with `images_to_add` and `images_to_subtract`.
img_sub_folder (str): A name for sub-folders within each fov in the image_data location.
fov_list: A list of fov's to create composite channels through.
images_to_add (List[str]): A list of channels or pixel cluster names to add together.
images_to_subtract (List[str]): A list of channels or pixel cluster names to subtract
from the composite.
image_type (str): Either "signal" or "pixel_cluster" data.
composite_method (str): Binarized mask returns ("binary") or intensity, gray-scale tiffs
returned ("total").
composite_directory (Union[str, pathlib.Path]): The directory to save the composite array.
composite_name (str): The name of the composite array to save.
log_dir: The directory to save log information to.

Returns:
np.ndarray: Saves the composite array, either as a binary mask, or as a scaled intensity array.
"""
for fov in fov_list:
# load in tiff images and verify channels are present
fov_data = load_utils.load_imgs_from_tree(
data_dir=image_data_dir, img_sub_folder=img_sub_folder, fovs=fov
)

image_shape = fov_data.shape[1:3]

misc_utils.verify_in_list(
images_to_add=images_to_add, image_names=fov_data.channels.values
)
misc_utils.verify_in_list(
images_to_subtract=images_to_subtract, image_names=fov_data.channels.values
)
misc_utils.verify_in_list(
composite_method=composite_method, options=["binary", "total"]
)

# make composite dir if not there already
if isinstance(composite_directory, str):
composite_directory = pathlib.Path(composite_directory)
composite_directory.mkdir(parents=True, exist_ok=True)

# Initialize composite array, and add & subtract channels
composite_array = np.zeros(shape=image_shape)
if images_to_add:
composite_array = add_to_composite(
fov_data, composite_array, images_to_add, image_type, composite_method
)
if images_to_subtract:
composite_array = subtract_from_composite(
fov_data, composite_array, images_to_subtract, image_type, composite_method
)

# Create the fov dir within the composite dir
composite_fov_dir = composite_directory / fov
composite_fov_dir.mkdir(parents=True, exist_ok=True)

# Save the composite image
image_utils.save_image(
fname=composite_directory / fov / f"{composite_name}.tiff",
data=composite_array.astype(np.uint32)
)

# Write a log saving composite builder info
variables_to_log = {
"image_data_dir": image_data_dir,
"fov_list": fov_list,
"images_to_add": images_to_add,
"images_to_subtract": images_to_subtract,
"image_type": image_type,
"composite_method": composite_method,
"composite_directory": composite_directory,
"composite_name": composite_name,
}
log_creator(variables_to_log, log_dir, f"{composite_name}_composite_log.txt")

print("Composites built and saved")


def add_to_composite(
data: xr.DataArray,
composite_array: np.ndarray,
images_to_add: List[str],
image_type: str,
composite_method: str,
) -> np.ndarray:
"""
Adds tiffs together to form a composite array.

Args:
data (xr.DataArray): The data array containing the set of all images which get filtered out
with `images_to_add`.
composite_array (np.ndarray): The array to add channels to.
images_to_add (List[str]): A list of channels or pixel cluster names to add together.
image_type (str): Either "signal" or "pixel_cluster" data.
composite_method (str): Binarized mask returns ("binary") or intensity, gray-scale tiffs
returned ("total").

Returns:
np.ndarray: The composite array, either as a binary mask, or as a scaled intensity array.
"""

filtered_channels: xr.DataArray = data.sel(
{"channels": images_to_add}).squeeze().astype(np.int32)
if len(images_to_add) > 1:
composite_array: np.ndarray = filtered_channels.sum(dim="channels").values
else:
composite_array: np.ndarray = filtered_channels
if image_type == "pixel_cluster" or composite_method == "binary":
composite_array = composite_array.clip(min=None, max=1)

return composite_array


def subtract_from_composite(
data: xr.DataArray,
composite_array: np.ndarray,
images_to_subtract: List[str],
image_type: str,
composite_method: str,
) -> np.ndarray:
"""
Subtracts tiffs from a composite array.

Args:
data (xr.DataArray): The data array containing the set of all images which get
filtered out with `images_to_subtract`.
composite_array (np.ndarray): An array to subtract channels from.
images_to_subtract (List[str]): A list of channels or pixel cluster names to subtract
from the composite.
image_type (str): Either "signal" or "pixel_cluster" data.
composite_method (str): Binarized mask returns ('binary') or intensity, gray-scale tiffs
returned ('total').

Returns:
np.ndarray: The composite array, either as a binary mask, or as a scaled intensity array.
"""

filtered_channels: xr.DataArray = data.sel(
{"channels": images_to_subtract}).squeeze().astype(np.int32)
if len(images_to_subtract) > 1:
composite_array2sub: np.ndarray = filtered_channels.sum(dim="channels").values
else:
composite_array2sub: np.ndarray = filtered_channels

if image_type == "signal" and composite_method == "binary":
mask_2_zero = composite_array2sub > 0
composite_array[mask_2_zero] = 0
composite_array[composite_array > 1] = 1

else:
composite_array -= composite_array2sub
composite_array = composite_array.clip(min=0, max=None)

return composite_array
Loading
Loading