adjunct_deob_around_origin didn't work? or not really an oblique problem?

AFNI version info (afni -ver): Version AFNI_24.3.05 'Elagabalus

Hiii, I have a mamorset MRI (carcass) trying to align to a T1 template. It shouldn't be a problem with animal_warper, but the result looks weird/distorted.

The final QC images don't look very good. (qc_02 I assume those are the final qc?)



as you can see, the sagittal part is a bit weird. It looks like there is an oblique (checked using 3dinfo -is_oblique got 1). but then I ran adjunct_deob_around_origin, the image remain the same.

here the first row is the template, the second raw is the carcass MRI. Maybe it's not an oblique problem? what would be the problem then? there is not sphinix problem either.

Thank you!

# Check if input file is oblique using 3dinfo
is_oblique=0
if [ "$(3dinfo -is_oblique "$input_file")" != "0" ]; then
    is_oblique=1
fi

if [ "$is_oblique" -eq 1 ]; then
    echo "Input file is oblique. Using adjunct_deob_around_origin to handle obliquity." >> "${stdout_log}"
    
    base_filename=$(strip_extension "$original_input_file")
    temp_prefix="${base_filename}_deob"
    echo "Base filename: $base_filename" >> "${stdout_log}"
    echo "Temp prefix: $temp_prefix" >> "${stdout_log}"
    
    # Run adjunct_deob_around_origin
    echo "Running adjunct_deob_around_origin..." >> "${stdout_log}"
    if ! adjunct_deob_around_origin -input "${original_input_file}" -prefix "${preproc_dir}/${temp_prefix}" >> "${stdout_log}" 2>> "${stderr_log}"; then
        echo "ERROR: adjunct_deob_around_origin failed" >> "${stderr_log}"
        exit 1
    fi
    
    # List files in output directory for debugging
    echo "Files in preprocessing directory:" >> "${stdout_log}"
    ls -l "${preproc_dir}" >> "${stdout_log}"
    
    # Check for AFNI format first (most likely output)
    if [ -f "${preproc_dir}/${temp_prefix}+orig.HEAD" ]; then
        echo "Found AFNI format file, converting to NIFTI..." >> "${stdout_log}"
        # Convert AFNI to NIFTI
        if ! 3dAFNItoNIFTI -prefix "${preproc_dir}/${temp_prefix}" "${preproc_dir}/${temp_prefix}+orig" >> "${stdout_log}" 2>> "${stderr_log}"; then
            echo "ERROR: Failed to convert AFNI to NIFTI" >> "${stderr_log}"
            exit 1
        fi
        # Wait for file to be created
        sleep 1
    fi
    
    # Now check for NIFTI files
    if [ -f "${preproc_dir}/${temp_prefix}.nii.gz" ]; then
        input_file="${preproc_dir}/${temp_prefix}.nii.gz"
    elif [ -f "${preproc_dir}/${temp_prefix}.nii" ]; then
        input_file="${preproc_dir}/${temp_prefix}.nii"
    else
        echo "ERROR: Could not find output file. Checked for:" >> "${stderr_log}"
        echo "  - ${preproc_dir}/${temp_prefix}.nii.gz" >> "${stderr_log}"
        echo "  - ${preproc_dir}/${temp_prefix}.nii" >> "${stderr_log}"
        echo "  - ${preproc_dir}/${temp_prefix}+orig.HEAD" >> "${stderr_log}"
        echo "Directory contents:" >> "${stderr_log}"
        ls -l "${preproc_dir}" >> "${stderr_log}"
        exit 1
    fi
    
    echo "Using deobliqued file: $input_file" >> "${stdout_log}"
else
    echo "Input file is not oblique. No deobliquing needed." >> "${stdout_log}"
    input_file="$original_input_file"
fi

animal_warper_cmd="@animal_warper -input \"$input_file\" -base \"$base_file\" -outdir \"$output_dir\" -skullstrip \"$skullstrip_file\" -ok_to_exist"

# Debug: Print the constructed command
echo "Running @animal_warper with the following command:" >> "${stdout_log}"
echo "$animal_warper_cmd" >> "${stdout_log}"

# Run the command using eval
eval "$animal_warper_cmd" >> "${stdout_log}" 2>> "${stderr_log}"

Howdy-

There are a few things brought up here.

I think I initially misunderstood what you are describing here, so please let me know if I have it correct. The top image you show is actually the result of @animal_warper aligning your input dataset to a template, is that right? It's not the input dset itself (which is what I thought it was in the beginning)?

For what QC images are what, the program help describes them---please see here. For the displayed brain+mask images that are qc_02*, the help describes:

qc_02.input+mask* (in input space)
  [ulay] input dset
  [olay] estimated (or input) mask, showing skullstripping

Looking at the qc_02*axi* image I was also confused, because it kind of didn't look "axial" to me. Looking at the qc_02*sag* image reveals there is a large degree of rotation in this dataset, with respect to usual view planes (something like AC-PC alignment). I think that is causing the poor alignment.

I guess this is a feature of the obliquity---normally people acquire data obliquely so that within the FOV, the brain has good planar-correspondence between the brain and the FOV slices. Therefore, deobliquing by purging obliquity rotations can make a lot of sense. I don't think taht is the case here. Can you please run this, where DSET_ANAT_ORIG is your original anatomical with obliquity still in it, and DSET_TEMPLATE is your reference template dset:

 @djunct_overlap_check \
    -ulay DSET_ANAT_ORIG \
    -olay DSET_TEMPLATE \
    -prefix img_olap

... and then post what should presumably be 2 images that are output (one ignoring obliquity and one applying obliquity)? That will help me judge how much obliquity is present and what it "does" within the dset.

Because carrying obliquity around is a pain for anatomical dsets, we often recommend removing it in a way that both preserves the coordinate origin (x,y,z)=(0,0,0) and does not blur it by resampling the grid; that is the role of adjunct_deob_around_origin. The before/after result won't appear different in the GUI, but the coordinate values in the "real" space of hte dset will be different. In this case, since the dset appears to have a lot of rotation within its deoblique frame (at least at present), we might have to consider other options. Let's see.

Thanks for posting those two rows of template+raw input dset images at the bottom---that is helpful. As per the description of how alignment works (see this AFNI Academy video on alignment considerations+principles), we also have to consider the fact that your input dset has differing contrast compared to the reference dset (as well as large relative rotation). That is, in the T1w template, the WM is the brightest tissue, then GM, then CSF. Your input dataset doesn't appear to have that as the case: the GM is brightest, then WM, then then CSF. So, we might have to use a different cost function for the alignment. My guess is that using -cost nmi will produce better results due to the differing contrasts.

Then we just have to ponder the relative rotation, but we can make a plan better when we see the overlap images, above.

And it would be great to see the command you are running, so we can make recommendations directly.

--pt

The problem seems to be the greater than 45 degrees tilt within the field of view of the sagittal image. Even with the "giant_move" of animal_warper, it won't search past 45 degrees. The problem is similar to the one we often encounter with animal scans, just not quite as obvious, where the animal is scanned in a sphinx position. You can run the desphinxify program to make a reoriented version of this, and see if that works better. The rotation angle will still be high, but it will be less than 45 degrees.

Hii, thank both of you.

@ptaylor i ran @djunct_overlap_check
here is the result


here is my command

@djunct_overlap_check \
    -ulay unna_mri+orig \
    -olay template_T1w+orig \
    -prefix img_olap

here is the txt output

# ulay         = unna_mri+orig
# ulay_is_obl  = 1
# ulay_obl_ang = 6.899
# mat44 Obliquity Transformation ::
      0.992759     -0.120123     -0.000000      -1.997538
      0.120123      0.992759     -0.000000      -3.394257
      0.000000      0.000000      1.000000       0.000000
# 
# olay         = template_T1w+orig
# olay_is_obl  = 1
# olay_obl_ang = 6.899
# mat44 Obliquity Transformation ::
      1.000000      0.000000      0.000000       0.000000
      0.000000      1.000000      0.000000      -0.000001
      0.000000      0.000000      1.000000       0.000000

@dglen then I ran desphinixify. I first set OM as RIP
desphinxify
-orient_mid RIP
-input unna_mri+orig
-prefix unna_mri_DSPH+orig
and got


the sagittal shifted to a wrong direction.

then I changed to RSA (I don't think this is correct; I picked an ostensibly correct one)
desphinxify
-orient_mid RSA
-input unna_mri+orig
-prefix unna_mri_DSPH_RSA+orig
and I got the following, which the sagittal part is overly shifted.

and yes @ptaylor I think you're correct that the Axial is not Axial... looks like I have two Coronal :melting_face:
for animal_warper, my command was simple (I attached it at the end of the first post).

animal_warper_cmd="@animal_warper -input \"$input_file\" -base \"$base_file\" -outdir \"$output_dir\" -skullstrip \"$skullstrip_file\" -ok_to_exist"

Also, I don't have qc_03 but only qc_02 so I thought qc_02 was the final output.

Something is probably wrong with the raw data. I didn't collect the data; I'm gonna ask them.

Howdy-

Thanks for sharing that. Sooo, there is obliquity here, but only a small amount (largest angle, 6.899 degrees). It's a bit odd to use obliquity when setting up the FOV, but then to not have the brain be well-aligned-planewise within the FOV, which is what we have here! That is what is shown by the overlap images:

  • img_olap shows the images when obliquity is ignored
  • img_olap_DEOB shows the images when obliquity is applied.

In both cases, the original space brain is turned far away from the template (this must be a shy subject!). This will present a challenge for alignment, because the source and base datasets for the alignment process are far away from each other in the 12 DoF affine parameter space, and there are a lot of structures present, meaning that it might be pretty easy to fall into a (false) local minimum during alignment.

From the command you have, it looks like you are applying a brainmask that you made in some way already---is that correct? How well does that brainmask overlap your original dset, and are they both deobliqued in the same way? What is the output of:

3dinfo -same_all_grid -header_line ${infile} ${skullstrip_file}

? That should report two rows of all 1s if they are on the same grid.

If they are on the same grid, then let's see what happens with the following:

@animal_warper \
     -input "$input_file" \
     -base "$base_file" \
     -outdir "$output_dir" \
     -skullstrip "$skullstrip_file" \
     -cost nmi    \
     -ok_to_exist

If you can have feedback on the acquisition for future scans, having the brain more plane-wise aligned with the FOV planes would be better---that is what obliquity is for, typically.

--pt

It looks like your second sphinxify output is closer, at least closer than the original. We're not expecting it to be aligned at this point. I would recommend starting with unna_mri_DSPH_RSA+orig then for the animal_warper input. The lpc, lpc+ZZ or the nmi cost functions would be good cost functions to try.

Thank you!
@dglen I'll use unna_mri_DSPH_RSA+orig for the alignment. so you mean even if we apply desphinxify, we don't expect everything to be perfect at the first step right.

@ptaylor speaking of ${skullstrip_file}, I think I might have misunderstood this argument. I used a brain mask (which was generated from the atlas group).


okay, so it should not be the brain mask?

-skullstrip brainmask
                      :one can provide a brainmask that is in the
                       base template space. This brainmask will be
                       warped back to native space and used to
                       skullstrip the original volume. This dataset
                       should share exactly the same grid as the
                       base template dataset.  (If this opt isn't
                       used to provide a brainmask, then the '-base
                       ..' volume itself will be used to do so.)

here is my result on input_file and skullstrip_file

3dinfo -same_all_grid -header_line ${input_file} ${skullstrip_file}
=dim?	=delt?	=ornt?	=cent?	=obl?
0	0	0	0	0
0	0	0	0	0

I also run the same command on the template (base file, if I didn't mix up base and source) and skullstrip_file

3dinfo -same_all_grid -header_line ${template_file} ${skullstrip_file}
=dim?	=delt?	=ornt?	=cent?	=obl?
1	1	1	1	1
1	1	1	1	1

and

3dinfo -is_oblique ${template_file}
0

so I used ${skullstrip_file} in the wrong way?

Also, I emailed the data collection person on "having the brain more plane-wise aligned with the FOV planes would be better"; I probably didn't say clearly that this subject's scan is ex vivo, yes, carcass. Do you have any other recommendations for such a scan?

Thank you!

Regarding:

Yes, that's right. It's just a way to get things close enough to a correct orientation to start. In the worst case, you can use the Nudge plugin or the 3drotate command to straighten the data out. We can even potentially incorporate that into the affine matrix from alignment.

So, I do mean to use that RSA dataset as your new input to @animal_warper.

The mask looks approximately right (although you're not viewing it in the AFNI GUI). It should be in the MBM template space, but it then gets applied to skullstrip your data.

Oh, goodness, I need to read the help files better. Yes, you are right, the -skullstrip .. mask is in standard space. Please ignore what I was putting about checking grid matching with the DSET_ANAT_ORIG.

Hii,
so i used unna_mri_DSPH_RSA + nmi as cost function rerun animal_warper,

Starting processing pipeline...
Input file: .../fusi/mri_unna/unna_mri_DSPH_RSA+orig
Output directory: .../fusi/mri_unna/aw_results2
Preprocessing directory: .../fusi/mri_unna/preproc_unna
Running @animal_warper with the following command:
@animal_warper -input ".../fusi/mri_unna/unna_mri_DSPH_RSA+orig" -base ".../fusi/atlas/template_T1w.nii.gz" -outdir ".../fusi/mri_unna/aw_results2" -skullstrip ".../fusi/atlas/mask_brain.nii.gz" -cost nmi -ok_to_exist

and got error at the warping stage

here is the relevant stdout.log part

#++ auto_warp.py version: 0.06
-- clearing AFNI_COMPRESSOR ...
# Output directory .../fusi/mri_unna/aw_results2/awpy_unna_mri_DSPH_RSA_pshft/
#Script is running (command trimmed):
  mkdir ./awpy_unna_mri_DSPH_RSA_pshft/
cd .../fusi/mri_unna/aw_results2/awpy_unna_mri_DSPH_RSA_pshft/
#Script is running (command trimmed):
  3dcopy .../fusi/mri_unna/aw_results2/intermediate/unna_mri_DSPH_RSA_shft_aff.nii.gz ./anat.nii
#Script is running (command trimmed):
  3dUnifize -GM -input ./anat.nii -prefix ./anat.un.nii
#Script is running (command trimmed):
  3dcopy .../fusi/atlas/template_T1w.nii.gz ./base.nii
#Script is running (command trimmed):
  3dAttribute DELTA ./anat.un.nii
#Script is running (command trimmed):
  3dAttribute DELTA ./base.nii
0.200000 0.200000
#Script is running (command trimmed):
  3dinfo -same_grid ./anat.un.nii ./base.nii
#++ Aligning .../fusi/mri_unna/aw_results2/awpy_unna_mri_DSPH_RSA_pshft/base.nii data to .../fusi/mri_unna/aw_results2/awpy_unna_mri_DSPH_RSA_pshft/anat.un.nii data
#Script is running (command trimmed):
  3dQwarp -prefix ./anat.un.qw.nii -blur -3 -3 -workhard:0:2 -iwarp \
 -maxlev 09 \
 -nmi -base ./base.nii -source ./anat.un.nii 
#**ERROR Failed in warping step
** ERROR - script failed
** ERROR: program failed (autowarp cp)

here is the relevant stderr.log part

AFNI QUITTs!
[1]    Done                          Xvfb :277 -screen 0 1024x768x24
+++ Transforming all input to rgb for a good reason 
+++ Writing image to ../init_qc_02.input_aff+base.jpg
++ 3dcopy: AFNI version=AFNI_24.3.05 (Oct 26 2024) [64-bit]
++ 3dUnifize: AFNI version=AFNI_24.3.05 (Oct 26 2024) [64-bit]
 + Pre-processing: ADVUWm
++ Output dataset ./anat.un.nii
++ ===== CPU time = 3.0 sec  Elapsed = 0.7
++ 3dcopy: AFNI version=AFNI_24.3.05 (Oct 26 2024) [64-bit]
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
++ OpenMP thread count = 12
++ 3dQwarp: AFNI version=AFNI_24.3.05 (Oct 26 2024) [64-bit]
++ Authored by: Zhark the (Hermite) Cubically Warped
e[7m** FATAL ERROR:e[0m 3dQwarp fails :: source image has 0 nonzero voxels (< 100)
** Program compile date = Oct 26 2024
3dcopy: No match.
3dcopy: No match.

sad, is it the same problem related to the rotation problem or a different problem?

Hm, I see. I have now reproduced this crash on my end, and will investigate.

--pt

1 Like

i found out that it was nmi that caused the crash. I changed it to lpc+zz, and the program finished, but the QC result doesn't look good.

init_qc_03.input_NL+base:

qc_02.input+mask.axi:

qc_02.input+mask.cor:

qc_02.input+mask.sag:

this was unna_mri_DSPH_RSA, probably still the orientation problem. i can try a different orientation later.