Skip to content

Commit 7b86d50

Browse files
committed
added option for 2D inter-section interpolation method and debugged use of final resolution
1 parent f11e7db commit 7b86d50

12 files changed

Lines changed: 195 additions & 143 deletions

brainbuilder/align/align_2d.py

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ def resample_reference_to_sections(
8383
if not os.path.exists(iso_output_fn) or not os.path.exists(output_fn) or clobber:
8484
# Apply 3d transformation to the reference volume
8585
rand = tempfile.NamedTemporaryFile().name
86+
8687
rand_fn = f"{rand}.nii.gz"
88+
8789
utils.simple_ants_apply_tfm(input_fn, ref_fn, tfm_inv_fn, rand_fn, ndim=3)
8890

8991
img = nib.load(rand_fn)
@@ -384,6 +386,7 @@ def align_2d_parallel(
384386
nib.load(row["2d_align_cls"]).get_fdata(), cmap="nipy_spectral", alpha=0.4
385387
)
386388
plt.savefig(f"{prefix}_qc.png")
389+
plt.close()
387390

388391
# assert np.sum(nib.load(prefix+'_cls_rsl.nii.gz').dataobj) > 0, 'Error: 2d affine transfromation failed'
389392
assert os.path.exists(
@@ -397,7 +400,9 @@ def apply_transforms_parallel(
397400
tfm_dir: str,
398401
resolution: float,
399402
row: pd.Series,
403+
tissue_str:str = '',
400404
file_str: str = "img",
405+
interpolation: str = "Linear",
401406
verbose: bool = False,
402407
) -> int:
403408
"""Apply transforms to 2d sections.
@@ -410,14 +415,20 @@ def apply_transforms_parallel(
410415
:param row: row
411416
:return: 0
412417
"""
418+
419+
out_fn = row["2d_align" + tissue_str]
420+
421+
if os.path.exists(out_fn):
422+
return out_fn
423+
413424
y = int(row["sample"])
425+
414426
base = row["base"]
415427

416428
prefix = f"{tfm_dir}/{base}_y-{y}"
417-
img_rsl_fn = f"{prefix}_{resolution}mm.nii.gz"
418-
out_fn = prefix + "_rsl.nii.gz"
419-
fx_fn = gen_2d_fn(prefix, "_fx")
420429

430+
img_rsl_fn = f"{prefix}_{resolution}mm{tissue_str}.nii.gz"
431+
421432
img_fn = row[file_str]
422433

423434
try:
@@ -428,34 +439,58 @@ def apply_transforms_parallel(
428439

429440
img_res = np.array([img.affine[0, 0], img.affine[1, 1]])
430441

442+
print(img_fn)
443+
print(img_res);
444+
431445
# if we're not at the final resolution, we need to downsample the image
432-
if resolution != img_res[0] and resolution != img_res[1]:
433-
sigma = utils.calculate_sigma_for_downsampling(resolution / img_res)
446+
if resolution != img_res[0] or resolution != img_res[1]:
434447

435-
vol = img.get_fdata()
448+
#sigma = utils.calculate_sigma_for_downsampling(resolution / img_res)
449+
#vol = img.get_fdata()
450+
#vol = gaussian_filter(vol, sigma)
436451

437-
vol = gaussian_filter(vol, sigma)
452+
resample_to_resolution(
453+
img_fn,
454+
[float(resolution), float(resolution)],
455+
order=2,
456+
output_filename = img_rsl_fn,
457+
)
438458

439-
nib.Nifti1Image(vol, img.affine, direction_order="lpi").to_filename(img_rsl_fn)
459+
#nib.Nifti1Image(vol, img.affine, direction_order="lpi").to_filename(img_rsl_fn)
440460
else:
441461
# if we're at the final resolution, we need to symlink the image
442-
# check if the symlink exists
443462

444463
# Check if the symlink exists and points to the correct file
445464
if os.path.islink(img_rsl_fn):
465+
446466
if os.readlink(img_rsl_fn) != img_fn:
447467
os.remove(img_rsl_fn)
448468
os.symlink(img_fn, img_rsl_fn)
469+
449470
elif not os.path.exists(img_rsl_fn):
450471
os.symlink(img_fn, img_rsl_fn)
472+
451473
# the symlink is just created to help qc if the user needs to check the moving image before alignment
452474
# however ITK does not support symlinks so we rename img_rsl_fn to the actual file name
453475
img_rsl_fn = img_fn
454476

455-
cmd = f"antsApplyTransforms -v {int(verbose)} -d 2 -n BSpline -i {img_rsl_fn} -r {fx_fn} -t {prefix}_Composite.h5 -o {out_fn} "
477+
478+
#fx_fn = gen_2d_fn(prefix, "_fx")
479+
fx_fn = img_rsl_fn
480+
481+
#tfm_fn ={prefix}_Composite.h5
482+
tfm_fn = row["2d_tfm"]
483+
484+
#out_fn = prefix + "_rsl.nii.gz"
485+
486+
487+
print(out_fn)
488+
cmd = f"antsApplyTransforms -v {int(verbose)} -d 2 -n {interpolation} -i {img_rsl_fn} -r {fx_fn} -t {tfm_fn} -o {out_fn} "
456489

457490
shell(cmd, True)
491+
458492
assert os.path.exists(f"{out_fn}"), "Error apply nl 2d tfm to img autoradiograph"
493+
459494
return out_fn
460495

461496

@@ -471,7 +506,7 @@ def get_align_2d_to_do(sect_info: pd.DataFrame, clobber: bool = False) -> tuple:
471506
to_do_sect_info = []
472507
to_do_resample_sect_info = []
473508

474-
for idx, (i, row) in enumerate(sect_info.iterrows()):
509+
for idx, (_, row) in enumerate(sect_info.iterrows()):
475510
cls_fn = row["2d_align_cls"]
476511
tfm_fn = row["2d_tfm"]
477512
out_fn = row["2d_align"]
@@ -502,7 +537,7 @@ def get_align_filenames(
502537
sect_info["2d_align"] = [""] * sect_info.shape[0]
503538
sect_info["2d_align_cls"] = [""] * sect_info.shape[0]
504539

505-
for idx, (i, row) in enumerate(sect_info.iterrows()):
540+
for idx, (_, row) in enumerate(sect_info.iterrows()):
506541
y = int(row["sample"])
507542
base = row["base"]
508543
prefix = f"{tfm_dir}/{base}_y-{y}"
@@ -522,7 +557,6 @@ def get_align_filenames(
522557

523558
def align_sections(
524559
sect_info: pd.DataFrame,
525-
mv_dir: str,
526560
output_dir: str,
527561
resolution: float,
528562
resolution_list: list,
@@ -531,6 +565,7 @@ def align_sections(
531565
file_to_align: str = "seg",
532566
use_syn: bool = True,
533567
num_cores: int = 0,
568+
interpolation: str = "Linear",
534569
verbose: bool = False,
535570
) -> None:
536571
"""Align sections to sections from reference volume using ANTs.
@@ -566,28 +601,26 @@ def align_sections(
566601
# get lists of files that need to be aligned and resampled
567602
to_do_sect_info, to_do_resample_sect_info = get_align_2d_to_do(sect_info)
568603

569-
last_resolution = resolution == resolution_list[-1]
570-
571604
if len(to_do_sect_info) > 0:
572605
Parallel(n_jobs=num_cores, backend="multiprocessing")(
573606
delayed(align_2d_parallel)(
574607
tfm_dir,
575608
resolution,
576609
resolution_list,
577610
row,
578-
base_lin_itr=base_lin_itr,
579-
base_nl_itr=base_nl_itr,
580-
file_to_align=file_to_align,
581-
use_syn=use_syn,
582-
verbose=verbose,
611+
base_lin_itr = base_lin_itr,
612+
base_nl_itr = base_nl_itr,
613+
file_to_align = file_to_align,
614+
use_syn = use_syn,
615+
verbose = verbose,
583616
)
584617
for row in to_do_sect_info
585618
)
586619

587620
if len(to_do_resample_sect_info) > 0:
588621
Parallel(n_jobs=num_cores, backend="multiprocessing")(
589622
delayed(apply_transforms_parallel)(
590-
tfm_dir, resolution, row, verbose=verbose
623+
tfm_dir, resolution, row, interpolation=interpolation, verbose=verbose
591624
)
592625
for row in to_do_resample_sect_info
593626
)
@@ -600,7 +633,7 @@ def concatenate_tfm_sections_to_volume(
600633
rec_fn: str,
601634
output_dir: str,
602635
out_fn: str,
603-
target_str: str = "rsl",
636+
target_str: str = "",
604637
) -> pd.DataFrame:
605638
"""Concatenate 2D sections into output volume.
606639
@@ -616,16 +649,16 @@ def concatenate_tfm_sections_to_volume(
616649
tfm_dir = output_dir + os.sep + "tfm"
617650

618651
hires_img = nib.load(rec_fn)
619-
target_name = "nl_2d_" + target_str
652+
target_name = "2d_align" + target_str
620653

621-
sect_info[target_name] = [""] * sect_info.shape[0]
654+
#sect_info[target_name] = [""] * sect_info.shape[0]
622655

623-
def set_target_name(base, y):
624-
return f"{tfm_dir}/{base}_y-{y}_{target_str}.nii.gz"
656+
#def set_target_name(base, y):
657+
# return f"{tfm_dir}/{base}_y-{y}_{target_str}.nii.gz"
625658

626-
sect_info[target_name] = sect_info.apply(
627-
lambda row: set_target_name(row["base"], int(row["sample"])), axis=1
628-
)
659+
#sect_info[target_name] = sect_info.apply(
660+
# lambda row: set_target_name(row["base"], int(row["sample"])), axis=1
661+
#)
629662

630663
concatenate_sections_to_volume(
631664
sect_info, target_name, out_fn, hires_img.shape, hires_img.affine
@@ -652,6 +685,7 @@ def align_2d(
652685
use_syn: bool = True,
653686
file_to_align: str = "seg",
654687
num_cores: int = 1,
688+
interpolation: str = "Linear",
655689
clobber: bool = False,
656690
) -> pd.DataFrame:
657691
"""Align 2D sections to sections from reference volume using ANTs.
@@ -679,6 +713,8 @@ def align_2d(
679713
"""
680714
ymax = sect_info["sample"].max()
681715

716+
# Apply 3D transformation to reference volume and resample to the resolution
717+
# of the reconstruction and to the section thickness along the y-axis
682718
_, ref_space_nat_fn = resample_reference_to_sections(
683719
float(resolution),
684720
ref_rsl_fn,
@@ -689,6 +725,7 @@ def align_2d(
689725
ymax=ymax,
690726
)
691727

728+
# Create 2D sections from the resampled reference volume
692729
utils.create_2d_sections(
693730
sect_info, ref_space_nat_fn, float(resolution), nl_2d_dir, dtype=np.uint8
694731
)
@@ -698,16 +735,17 @@ def align_2d(
698735
lambda x: os.path.basename(x).split(".")[0]
699736
)
700737

738+
# Align 2D sections to sections from reference volume using ANTs
701739
sect_info = align_sections(
702740
sect_info,
703-
seg_dir + "/2d/",
704741
nl_2d_dir,
705742
resolution,
706743
resolution_list,
707744
use_syn=use_syn,
708745
base_lin_itr=base_lin_itr,
709746
base_nl_itr=base_nl_itr,
710747
num_cores=num_cores,
748+
interpolation=interpolation,
711749
file_to_align=file_to_align,
712750
)
713751

@@ -718,7 +756,7 @@ def align_2d(
718756

719757
# Concatenate 2D nonlinear aligned cls sections into an output volume
720758
sect_info = concatenate_tfm_sections_to_volume(
721-
sect_info, ref_space_nat_fn, nl_2d_dir, nl_2d_cls_fn, target_str="cls_rsl"
759+
sect_info, ref_space_nat_fn, nl_2d_dir, nl_2d_cls_fn, target_str="_cls"
722760
)
723761

724762
return sect_info, ref_space_nat_fn

brainbuilder/align/intervolume.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,13 @@ def resample_and_transform(
9292
seg_rsl_fn = get_seg_fn(
9393
output_dir, int(row["sample"]), resolution_2d, seg_fn, "_rsl"
9494
)
95+
9596
seg_rsl_tfm_fn = get_seg_fn(
9697
output_dir, int(row["sample"]), resolution_3d, seg_fn, "_rsl_tfm"
9798
)
99+
98100
if not os.path.exists(seg_rsl_tfm_fn) or clobber:
101+
99102
tfm_input_fn = get_input_file(
100103
seg_fn, seg_rsl_fn, row, output_dir, resolution_2d, resolution_3d
101104
)
@@ -121,8 +124,7 @@ def resample_and_transform(
121124
print("\tNo transform for", seg_rsl_fn)
122125
shutil.copy(tfm_input_fn, seg_rsl_tfm_fn)
123126

124-
row["nl_2d_cls_rsl"] = seg_rsl_tfm_fn
125-
row["nl_2d_rsl"] = seg_rsl_tfm_fn
127+
row["seg_rsl"] = seg_rsl_tfm_fn
126128

127129
return row
128130

@@ -152,11 +154,9 @@ def resample_transform_segmented_images(
152154
tfm_ref_fn = output_dir + "/2d_reference_image.nii.gz"
153155

154156
if not os.path.exists(tfm_ref_fn) and resolution_itr != 0:
155-
ref_img = nib.load(sect_info["nl_2d_rsl"].values[0])
156-
xstart, zstart = ref_img.affine[[0, 1], 3]
157157

158158
resample_to_resolution(
159-
sect_info["nl_2d_rsl"].values[0],
159+
sect_info["seg_rsl"].values[0],
160160
[resolution_3d] * 2,
161161
tfm_ref_fn,
162162
order=0,
@@ -370,7 +370,7 @@ def create_intermediate_volume(
370370
affine[2, 2] = resolution_3d
371371

372372
concatenate_sections_to_volume(
373-
sect_info, "nl_2d_rsl", curr_align_fn, dims, affine
373+
sect_info, "seg_rsl", curr_align_fn, dims, affine
374374
)
375375

376376
chunk_info["nl_2d_vol_fn"] = curr_align_fn

brainbuilder/initalign.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ def align_neighbours_to_fixed(
7575

7676
# calculate rigid transform from moving to fixed images
7777
if not os.path.exists(tfm_fn) or not os.path.exists(qc_fn):
78-
logger.info()
79-
logger.info(f"\tFixed: {i} {fixed_fn}")
78+
logger.info(f"\n\tFixed: {i} {fixed_fn}")
8079
logger.info(f"\tMoving: {j} {moving_fn}")
8180
logger.info(f"\tTfm: {tfm_fn} {os.path.exists(tfm_fn)}")
8281
logger.info(f"\tQC: {qc_fn} {os.path.exists(qc_fn)}")
@@ -689,7 +688,7 @@ def align_chunk(
689688
df["original_img"] = df["img"]
690689

691690
acquisition_contrast_order = get_acquisition_contrast_order(sect_info)
692-
logger.info("\tAcquistion contrast order: ", acquisition_contrast_order)
691+
logger.info(f"\tAcquistion contrast order: {acquisition_contrast_order}")
693692

694693
df["tier"] = 1
695694

@@ -777,9 +776,6 @@ def align_chunk(
777776

778777
concat_list.append(df_acquisition.loc[df_acquisition["tier"] == 2])
779778

780-
# logger.info(target_acquisition)
781-
# logger.info(df_acquisition['init_tfm'].loc[ df['acquisition'] == target_acquisition ])
782-
783779
# update the master dataframe, df, with new dataframe for the acquisition
784780
df.loc[df["acquisition"] == target_acquisition] = df_acquisition.loc[
785781
df["acquisition"] == target_acquisition

0 commit comments

Comments
 (0)