# qform transformation

Dear all,

I have depicted a ROI over a T1w nifti file so the ROI is saved in a nifti file with a head copied from the original T1w volume.

I want to compute some statistics over other nifti volume (ADC volume) using that ROI. In order to project the ROI on that volume and compute the histograms I use a R script.

I use (qform_ADC)^-1 * qform_ROI as transformation matrix from the ijk space of the ROI to the ijk space of the ADC. Is this correct?
(“*” means matrix product, “^-1” means matrix inverse)

I tried to label a slice of one ventricle and I look where this region is moved on the ADC, it does not match with that region on

Any help will be appreciated.

Félix.

You may want to use the sform matrix instead if that’s defined for your dataset. The concatenation of the matrice as the matrix product looks close to right as you want to do something like this:

ijk1 → xyz1 → ijk2

The ijk2 would need to be rounded to an integer. The function in R may take the reverse order. In AFNI,you can do something similar with cat_matvec and Vecwarp. cat_matvec concatenates 4x3 affine matrices. The sform_matrix in the NIFTI header and the equivalent IJK_TO_DICOM_REAL in the AFNI header defined for RAI xyz coordinates may be used to compute the ijk indices across datasets.

# extract the attribute that defines the ijk->xyz attribute from an AFNI dataset (and NIFTI datasets read by AFNI)

cat_matvec anat+orig::IJK_TO_DICOM_REAL > ijk1.1D

# compute the inverse, the xyz->ijk transformation

cat_matvec anat+orig::IJK_TO_DICOM_REAL -I > ijk1i.1D

cat > test.1D

# see what the xyz coordinates are given a set of ijk coordinates

Vecwarp -input test.1D -matvec ijk1.1D -output xyz1.1D

# multiply to see that multiplying by the inverse gives close to the identity matrix (decimal place rounding makes this inexact)

cat_matvec ijk1.1D ijk1i.1D
cat_matvec ijk1i.1D ijk1.1D

# extract the same transformation matrices from the second dataset

cat_matvec func_slim+orig.::IJK_TO_DICOM_REAL > ijk2.1D
cat_matvec func_slim+orig.::IJK_TO_DICOM_REAL -I > ijk2i.1D

# compute the matrix that defines ijk1->xyz->ijk2

cat_matvec ijk1.1D ijk2i.1D > ijk1xyz2a.1D
Vecwarp -input test.1D -matvec ijk1xyz2a.1D -output ijkxyz2aout.1D

# go to specific ijk in controller A, see closest ijk in controller B

afni

A couple caveats and some more advice:

1. The sform_matrix is defined for LPI order xyz coordinates. That’s different from the RAI coordinates of the IJK_TO_DICOM_REAL attribute.

2. Splitting up the problem is okay here. Compute the xyz coordinates separately given ijk. Then compute ijk for the second dataset given those xyz coordinates as a separate step and as a sanity check.

3. Oblique datasets may be slightly confusing in the GUI. The GUI doesn’t do these ijk->xyz coordinates using the same transformation. It instead uses the xyz coordinates from the closest cardinal transformation matrix. You can deoblique both datasets with “3dWarp -deoblique” to remove that point of confusion.

4. ijk and xyz coordinates can both be include in the output using 3dmaskdump (again using the cardinal matrix).

5. The R function may take the same order as cat_matvec, but it could be the reverse order. Also the Vecwarp command assumes the forward direction. It will invert that with the -backward option, and there may be something similar for the R function.

Thank you very much for your answer. It seems that the operation (after rounding) is conceptually correct.