Skip to content

Commit

Permalink
first draft of symmetrical 50um blackcap atlas
Browse files Browse the repository at this point in the history
  • Loading branch information
alessandrofelder committed Jun 27, 2024
1 parent 6a4f7ab commit 5ba829a
Showing 1 changed file with 256 additions and 0 deletions.
256 changes: 256 additions & 0 deletions brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
__version__ = "0"

Check warning on line 1 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L1

Added line #L1 was not covered by tests

import glob as glob
import os
import time
from pathlib import Path

Check warning on line 6 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L3-L6

Added lines #L3 - L6 were not covered by tests

import numpy as np
import pandas as pd
from brainglobe_utils.IO.image import load_nii
from rich.progress import track
from scipy import ndimage
from skimage.filters.rank import median
from skimage.morphology import ball

Check warning on line 14 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L8-L14

Added lines #L8 - L14 were not covered by tests

from brainglobe_atlasapi.atlas_generation.mesh_utils import (

Check warning on line 16 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L16

Added line #L16 was not covered by tests
Region,
create_region_mesh,
)
from brainglobe_atlasapi.atlas_generation.wrapup import wrapup_atlas_from_data
from brainglobe_atlasapi.structure_tree_util import get_structures_tree

Check warning on line 21 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L20-L21

Added lines #L20 - L21 were not covered by tests


def create_atlas(working_dir, resolution):
ATLAS_NAME = "oldenburg_blackcap"
SPECIES = "Sylvia atricapilla"
ATLAS_LINK = "https://uol.de/en/ibu/animal-navigation"
CITATION = "unpublished"
ATLAS_FILE_URL = "https://uol.de/en/ibu/animal-navigation" # noqa
ORIENTATION = "asr"
ROOT_ID = 999
ATLAS_PACKAGER = "BrainGlobe Developers, [email protected]"
ADDITIONAL_METADATA = {}

Check warning on line 33 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L24-L33

Added lines #L24 - L33 were not covered by tests

# setup folder for downloading

atlas_path = Path(

Check warning on line 37 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L37

Added line #L37 was not covered by tests
"/media/ceph-neuroinformatics/neuroinformatics/atlas-forge/BlackCap/templates/template_sym_res-50um_n-18/for_atlas/"
)

structures_file = atlas_path / "Label_description_BC74white_16_02_2024.txt"
annotations_file = (

Check warning on line 42 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L41-L42

Added lines #L41 - L42 were not covered by tests
atlas_path / "sub-BC74_res-50um_labels_aligned-to-reference.nii.gz"
)
reference_file = atlas_path / "reference_res-50um_image.nii.gz"
reference_mask_file = atlas_path / "reference_res-50um_mask-4reg.nii.gz"
meshes_dir_path = Path.home() / "blackcap-meshes"

Check warning on line 47 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L45-L47

Added lines #L45 - L47 were not covered by tests

try:
os.mkdir(meshes_dir_path)
except FileExistsError:
"mesh folder already exists"

Check warning on line 52 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L49-L52

Added lines #L49 - L52 were not covered by tests

# Read structures file
print("Reading structures file")
with open(

Check warning on line 56 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L55-L56

Added lines #L55 - L56 were not covered by tests
structures_file, mode="r", encoding="utf-8-sig"
) as blackcap_file:
structure_data = pd.read_csv(

Check warning on line 59 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L59

Added line #L59 was not covered by tests
blackcap_file,
delimiter="\s+",
comment="#",
names=["IDX", "R", "G", "B", "A", "VIS", "MESH_VIS", "LABEL"],
)

# replace Clear Label (first row) with a root entry
structure_data["LABEL"].iloc[0] = "root"
structure_data["R"].iloc[0] = 255
structure_data["G"].iloc[0] = 255
structure_data["B"].iloc[0] = 255
structure_data["IDX"].iloc[0] = 999

Check warning on line 71 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L67-L71

Added lines #L67 - L71 were not covered by tests

structure_data.rename(columns={"IDX": "id"}, inplace=True)
structure_data.rename(columns={"LABEL": "acronym"}, inplace=True)
structure_data["name"] = structure_data.apply(

Check warning on line 75 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L73-L75

Added lines #L73 - L75 were not covered by tests
lambda row: row["acronym"], axis=1
)
structure_data["rgb_triplet"] = structure_data.apply(

Check warning on line 78 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L78

Added line #L78 was not covered by tests
lambda row: [str(row["R"]), str(row["G"]), str(row["B"])], axis=1
)
structure_data["structure_id_path"] = structure_data.apply(

Check warning on line 81 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L81

Added line #L81 was not covered by tests
lambda row: [row["id"]] if row["id"] == 999 else [999, row["id"]],
axis=1,
)

# drop columns we don't need
structure_data.drop(

Check warning on line 87 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L87

Added line #L87 was not covered by tests
columns=["A", "VIS", "MESH_VIS", "R", "G", "B"], inplace=True
)

structure_data_list = []
for _, row in structure_data.iterrows():
structure_data_list.append(

Check warning on line 93 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L91-L93

Added lines #L91 - L93 were not covered by tests
{
"id": row["id"],
"rgb_triplet": row["rgb_triplet"],
# "parent_structure_id": row["parent_structure_id"],
"name": row["name"],
"structure_id_path": row["structure_id_path"],
"acronym": row["acronym"],
}
)

tree = get_structures_tree(structure_data_list)
print(

Check warning on line 105 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L104-L105

Added lines #L104 - L105 were not covered by tests
f"Number of brain regions: {tree.size()}, "
f"max tree depth: {tree.depth()}"
)
print(tree)
print(f"Saving atlas data at {atlas_path}")

Check warning on line 110 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L109-L110

Added lines #L109 - L110 were not covered by tests

# use tifffile to read annotated file
annotated_volume = load_nii(annotations_file, as_array=True).astype(

Check warning on line 113 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L113

Added line #L113 was not covered by tests
np.uint8
)

# remove unconnected components
label_im, nb_labels = ndimage.label(

Check warning on line 118 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L118

Added line #L118 was not covered by tests
annotated_volume
) # not to be confused with our labels
sizes = ndimage.sum(annotated_volume > 0, label_im, range(nb_labels + 1))
mask = sizes > 1000
annotated_volume *= mask[label_im]

Check warning on line 123 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L121-L123

Added lines #L121 - L123 were not covered by tests

# naive forcing symmetry
extent_LR = annotated_volume.shape[2]
half_image = extent_LR // 2

Check warning on line 127 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L126-L127

Added lines #L126 - L127 were not covered by tests

flipped_first_half = np.flip(

Check warning on line 129 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L129

Added line #L129 was not covered by tests
annotated_volume[:, :, 0:half_image], axis=2
).copy()
flipped_second_half = np.flip(

Check warning on line 132 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L132

Added line #L132 was not covered by tests
annotated_volume[:, :, half_image - 1 : -1], axis=2
).copy()

annotated_volume[:, :, 0:half_image] = np.minimum(

Check warning on line 136 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L136

Added line #L136 was not covered by tests
annotated_volume[:, :, 0:half_image], flipped_second_half
)
annotated_volume[:, :, half_image - 1 : -1] = np.minimum(

Check warning on line 139 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L139

Added line #L139 was not covered by tests
annotated_volume[:, :, half_image - 1 : -1], flipped_first_half
)

# smooth annotations
annotated_volume = median(

Check warning on line 144 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L144

Added line #L144 was not covered by tests
annotated_volume, ball(3), mask=annotated_volume > 0
)

# keep only annotations in mask
brain_mask = load_nii(reference_mask_file, as_array=True).astype(np.uint16)
annotated_volume *= brain_mask

Check warning on line 150 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L149-L150

Added lines #L149 - L150 were not covered by tests

# rescale reference volume into int16 range
reference_volume = load_nii(reference_file, as_array=True)
dmin = np.min(reference_volume)
dmax = np.max(reference_volume)
drange = dmax - dmin
dscale = (2**16 - 1) / drange
reference_volume = (reference_volume - dmin) * dscale
reference_volume = reference_volume.astype(np.uint16)

Check warning on line 159 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L153-L159

Added lines #L153 - L159 were not covered by tests

# generate binary mask for mesh creation
labels = np.unique(annotated_volume).astype(np.int_)
for key, node in tree.nodes.items():
if key in labels:
is_label = True

Check warning on line 165 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L162-L165

Added lines #L162 - L165 were not covered by tests
else:
is_label = False

Check warning on line 167 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L167

Added line #L167 was not covered by tests

node.data = Region(is_label)

Check warning on line 169 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L169

Added line #L169 was not covered by tests

# mesh creation
closing_n_iters = 2
decimate_fraction = 0.3
smooth = True

Check warning on line 174 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L172-L174

Added lines #L172 - L174 were not covered by tests

start = time.time()

Check warning on line 176 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L176

Added line #L176 was not covered by tests

for node in track(

Check warning on line 178 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L178

Added line #L178 was not covered by tests
tree.nodes.values(),
total=tree.size(),
description="Creating meshes",
):
create_region_mesh(

Check warning on line 183 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L183

Added line #L183 was not covered by tests
(
meshes_dir_path,
node,
tree,
labels,
annotated_volume,
ROOT_ID,
closing_n_iters,
decimate_fraction,
smooth,
)
)

print(

Check warning on line 197 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L197

Added line #L197 was not covered by tests
"Finished mesh extraction in : ",
round((time.time() - start) / 60, 2),
" minutes",
)

# create meshes dict
meshes_dict = dict()
structures_with_mesh = []
for s in structure_data_list:

Check warning on line 206 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L204-L206

Added lines #L204 - L206 were not covered by tests
# check if a mesh was created
mesh_path = meshes_dir_path / f"{s['id']}.obj"
if not mesh_path.exists():
print(f"No mesh file exists for: {s}, ignoring it.")
continue

Check warning on line 211 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L208-L211

Added lines #L208 - L211 were not covered by tests
else:
# check that the mesh actually exists and isn't empty
if mesh_path.stat().st_size < 512:
print(f"obj file for {s} is too small, ignoring it.")
continue
structures_with_mesh.append(s)
meshes_dict[s["id"]] = mesh_path

Check warning on line 218 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L214-L218

Added lines #L214 - L218 were not covered by tests

print(

Check warning on line 220 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L220

Added line #L220 was not covered by tests
f"In the end, {len(structures_with_mesh)} "
"structures with mesh are kept"
)

output_filename = wrapup_atlas_from_data(

Check warning on line 225 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L225

Added line #L225 was not covered by tests
atlas_name=ATLAS_NAME,
atlas_minor_version=__version__,
citation=CITATION,
atlas_link=ATLAS_LINK,
species=SPECIES,
resolution=resolution,
orientation=ORIENTATION,
root_id=999,
reference_stack=reference_volume,
annotation_stack=annotated_volume,
structures_list=structure_data_list,
meshes_dict=meshes_dict,
scale_meshes=True,
working_dir=working_dir,
hemispheres_stack=None,
cleanup_files=False,
compress=True,
atlas_packager=ATLAS_PACKAGER,
additional_metadata=ADDITIONAL_METADATA,
)

return output_filename

Check warning on line 247 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L247

Added line #L247 was not covered by tests


if __name__ == "__main__":
res = 50, 50, 50
home = str(Path.home())
bg_root_dir = Path.home() / "bg-atlasgen"
bg_root_dir.mkdir(exist_ok=True, parents=True)

Check warning on line 254 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L250-L254

Added lines #L250 - L254 were not covered by tests

create_atlas(bg_root_dir, res)

Check warning on line 256 in brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py

View check run for this annotation

Codecov / codecov/patch

brainglobe_atlasapi/atlas_generation/atlas_scripts/blackcap.py#L256

Added line #L256 was not covered by tests

0 comments on commit 5ba829a

Please sign in to comment.