Skip to content

Commit 51165a5

Browse files
Fix issues with the segmentation export to IMOD
1 parent 9b8c7a2 commit 51165a5

File tree

4 files changed

+162
-32
lines changed

4 files changed

+162
-32
lines changed

scripts/cooper/export_mask_to_imod.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,11 @@
44

55

66
def export_mask_to_imod(args):
7-
# Test script
8-
# write_segmentation_to_imod(
9-
# "synapse-examples/36859_J1_66K_TS_CA3_PS_26_rec_2Kb1dawbp_crop.mrc",
10-
# "synapse-examples/36859_J1_66K_TS_CA3_PS_26_rec_2Kb1dawbp_crop_mitos.tif",
11-
# "synapse-examples/mito.mod"
12-
# )
137
write_segmentation_to_imod(args.input_path, args.segmentation_path, args.output_path)
148

159

1610
def main():
1711
parser = argparse.ArgumentParser()
18-
19-
args = parser.parse_args()
2012
parser.add_argument(
2113
"-i", "--input_path", required=True,
2214
help="The filepath to the mrc file containing the data."

scripts/inner_ear/analysis/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
panels/
2+
auto_seg_export/
23
*.zip
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import os
2+
from shutil import copyfile
3+
from subprocess import run
4+
5+
import imageio.v3 as imageio
6+
import mrcfile
7+
import napari
8+
import numpy as np
9+
import pandas as pd
10+
from elf.io import open_file
11+
from skimage.transform import resize
12+
from synaptic_reconstruction.imod.to_imod import write_segmentation_to_imod, write_segmentation_to_imod_as_points
13+
14+
out_folder = "./auto_seg_export"
15+
os.makedirs(out_folder, exist_ok=True)
16+
17+
18+
def _resize(seg, tomo_path):
19+
with open_file(tomo_path, "r") as f:
20+
shape = f["data"].shape
21+
22+
if shape != seg.shape:
23+
seg = resize(seg, shape, order=0, anti_aliasing=False, preserve_range=True).astype(seg.dtype)
24+
assert seg.shape == shape
25+
return seg
26+
27+
28+
def check_imod(tomo_path, mod_path):
29+
run(["imod", tomo_path, mod_path])
30+
31+
32+
def export_pool(pool_name, pool_seg, tomo_path):
33+
seg_path = f"./auto_seg_export/{pool_name}.tif"
34+
pool_seg = _resize(pool_seg, tomo_path)
35+
imageio.imwrite(seg_path, pool_seg, compression="zlib")
36+
37+
output_path = f"./auto_seg_export/{pool_name}.mod"
38+
write_segmentation_to_imod_as_points(tomo_path, seg_path, output_path, min_radius=5)
39+
40+
check_imod(tomo_path, output_path)
41+
42+
43+
def export_vesicles(folder, tomo_path):
44+
vesicle_pool_path = os.path.join(folder, "Korrektur", "vesicle_pools.tif")
45+
# pool_correction_path = os.path.join(folder, "Korrektur", "pool_correction.tif")
46+
# pool_correction = imageio.imread(pool_correction_path)
47+
48+
assignment_path = os.path.join(folder, "Korrektur", "measurements.xlsx")
49+
assignments = pd.read_excel(assignment_path)
50+
51+
vesicles = imageio.imread(vesicle_pool_path)
52+
53+
pools = {}
54+
for pool_name in pd.unique(assignments.pool):
55+
pool_ids = assignments[assignments.pool == pool_name].id.values
56+
pool_seg = vesicles.copy()
57+
pool_seg[~np.isin(vesicles, pool_ids)] = 0
58+
pools[pool_name] = pool_seg
59+
60+
view = False
61+
if view:
62+
v = napari.Viewer()
63+
v.add_labels(vesicles, visible=False)
64+
for pool_name, pool_seg in pools.items():
65+
v.add_labels(pool_seg, name=pool_name)
66+
napari.run()
67+
else:
68+
for pool_name, pool_seg in pools.items():
69+
export_pool(pool_name, pool_seg, tomo_path)
70+
71+
72+
def export_structure(folder, tomo, name, view=False):
73+
path = os.path.join(folder, "Korrektur", f"{name}.tif")
74+
seg = imageio.imread(path)
75+
seg = _resize(seg, tomo)
76+
77+
if view:
78+
with open_file(tomo, "r") as f:
79+
raw = f["data"][:]
80+
81+
v = napari.Viewer()
82+
v.add_image(raw)
83+
v.add_labels(seg)
84+
napari.run()
85+
86+
return
87+
88+
seg_path = f"./auto_seg_export/{name}.tif"
89+
imageio.imwrite(seg_path, seg, compression="zlib")
90+
output_path = f"./auto_seg_export/{name}.mod"
91+
write_segmentation_to_imod(tomo, seg_path, output_path)
92+
check_imod(tomo, output_path)
93+
94+
95+
def remove_scale(tomo):
96+
new_path = "./auto_seg_export/Emb71M1aGridA1sec1mod7.rec.rec"
97+
if os.path.exists(new_path):
98+
return new_path
99+
100+
copyfile(tomo, new_path)
101+
102+
with mrcfile.open(new_path, "r+") as f:
103+
# Set the origin to (0, 0, 0)
104+
f.header.nxstart = 0
105+
f.header.nystart = 0
106+
f.header.nzstart = 0
107+
f.header.origin = (0.0, 0.0, 0.0)
108+
109+
# Save changes
110+
f.flush()
111+
112+
return new_path
113+
114+
115+
def main():
116+
folder = "/home/pape/Work/data/moser/em-synapses/Electron-Microscopy-Susi/Analyse/WT strong stim/Mouse 1/modiolar/1"
117+
tomo = os.path.join(folder, "Emb71M1aGridA1sec1mod7.rec.rec")
118+
119+
tomo = remove_scale(tomo)
120+
121+
# export_vesicles(folder, tomo)
122+
# export_structure(folder, tomo, "ribbon", view=False)
123+
# export_structure(folder, tomo, "membrane", view=False)
124+
export_structure(folder, tomo, "PD", view=False)
125+
126+
127+
if __name__ == "__main__":
128+
main()

synaptic_reconstruction/imod/to_imod.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,60 @@
1616
from tqdm import tqdm
1717

1818

19-
# FIXME how to bring the data to the IMOD axis convention?
20-
def _to_imod_order(data):
21-
# data = np.swapaxes(data, 0, -1)
22-
# data = np.fliplr(data)
23-
# data = np.swapaxes(data, 0, -1)
24-
return data
25-
26-
19+
# TODO: this has still some issues with some tomograms that has an offset info.
20+
# For now, this occurs for the inner ear data tomograms; it works for Fidi's STEM tomograms.
21+
# Ben's theory is that this might be due to data form JEOL vs. ThermoFischer microscopes.
22+
# To test this I can check how it works for data from Maus et al. / Imig et al., which were taken on a JEOL.
23+
# Can also check out the mrc documentation here: https://www.ccpem.ac.uk/mrc_format/mrc2014.php
2724
def write_segmentation_to_imod(
2825
mrc_path: str,
29-
segmentation_path: str,
26+
segmentation: Union[str, np.ndarray],
3027
output_path: str,
3128
) -> None:
32-
"""Write a segmentation to a mod file as contours.
29+
"""Write a segmentation to a mod file as closed contour objects.
3330
3431
Args:
35-
mrc_path: a
36-
segmentation_path: a
37-
output_path: a
32+
mrc_path: The filepath to the mrc file from which the segmentation was derived.
33+
segmentation: The segmentation (either as numpy array or filepath to a .tif file).
34+
output_path: The output path where the mod file will be saved.
3835
"""
3936
cmd = "imodauto"
4037
cmd_path = shutil.which(cmd)
4138
assert cmd_path is not None, f"Could not find the {cmd} imod command."
4239

40+
# Load the segmentation from a tif file in case a filepath was passed.
41+
if isinstance(segmentation, str):
42+
assert os.path.exists(segmentation)
43+
segmentation = imageio.imread(segmentation)
44+
45+
# Binarize the segmentation and flip its axes to match the IMOD axis convention.
46+
segmentation = (segmentation > 0).astype("uint8")
47+
segmentation = np.flip(segmentation, axis=1)
48+
49+
# Read the voxel size and origin information from the mrc file.
4350
assert os.path.exists(mrc_path)
44-
with mrcfile.open(mrc_path, mode="r+") as f:
51+
with mrcfile.open(mrc_path, mode="r") as f:
4552
voxel_size = f.voxel_size
53+
nx, ny, nz = f.header.nxstart, f.header.nystart, f.header.nzstart
54+
origin = f.header.origin
4655

56+
# Write the input for imodauto to a temporary mrc file.
4757
with tempfile.NamedTemporaryFile(suffix=".mrc") as f:
4858
tmp_path = f.name
4959

50-
seg = (imageio.imread(segmentation_path) > 0).astype("uint8")
51-
seg_ = _to_imod_order(seg)
52-
53-
# import napari
54-
# v = napari.Viewer()
55-
# v.add_image(seg)
56-
# v.add_labels(seg_)
57-
# napari.run()
58-
59-
mrcfile.new(tmp_path, data=seg_, overwrite=True)
60+
mrcfile.new(tmp_path, data=segmentation, overwrite=True)
61+
# Write the voxel_size and origin infomration.
6062
with mrcfile.open(tmp_path, mode="r+") as f:
6163
f.voxel_size = voxel_size
64+
65+
f.header.nxstart = nx
66+
f.header.nystart = ny
67+
f.header.nzstart = nz
68+
f.header.origin = (0.0, 0.0, 0.0) * 3 if origin is None else origin
69+
6270
f.update_header_from_data()
6371

72+
# Run the command.
6473
cmd_list = [cmd, "-E", "1", "-u", tmp_path, output_path]
6574
run(cmd_list)
6675

0 commit comments

Comments
 (0)