Determining BIDS PhaseEncodingDirection from DICOM

python
bids

#1

I’m converting some data from DICOM into a BIDS (or pre-BIDS) format using Python and AFNI tools, and one remaining snag is determining the phase encoding direction (BIDS term “PhaseEncodingDirection”) of distortion correction scans from the information in their DICOM headers. dcm2niix does generate a PhaseEncodingDirection entry in its JSON sidecar, but I can’t figure out how the utility is determining that information.

Does anyone know how to determine BIDS-style PhaseEncodingDirection information from DICOM headers without relying exclusively on dcm2niix?


#2

@dewarren looks like DICOM tag (0018, 1312) InPlanePhaseEncodingDirection is what you’re looking for.


#3

@mgxd Thanks for the response. That would make sense, but I’ll quote the BIDS spec (my emphasis):

PhaseEncodingDirection : Possible values: “i”, “j”, “k”, “i-”, “j-”, “k-”. The letters “i”, “j”, “k” correspond to the first, second and third axis of the data in the NIFTI file. The polarity of the phase encoding is assumed to go from zero index to maximum index unless ‘-’ sign is present (then the order is reversed - starting from the highest index instead of zero). PhaseEncodingDirection is defined as the direction along which phase is was modulated which may result in visible distortions. Note that this is not the same as the DICOM term InPlanePhaseEncodingDirection which can have “ROW” or “COL” values. This parameter is required if a corresponding fieldmap data is present or when using multiple runs with different phase encoding directions (which can be later used for field inhomogeneity correction).


#4

If you use Matlab, you can get this easily using dicm2nii - it should provide the same solution as dcm2niix. However, since you mention using Python I think the process will be more involved. You can use the excellent dcmstack to get the DICOM details. DICOM tag 0018,1312 will tell you if the phase encoding is in the Column or Row direction (the NIfTI i and j voxel dimensions; though some FSL tools refer to these as x and y voxel dimensions [which should not be confused with the MNI spatial dimensions of the same name]). Now you need to determine the polarity of the phase encoding. This varies for vendor, but assuming you are using Siemens this will be the tag “PhaseEncodingDirectionPositive” from the private CSA header (Python details at http://nipy.org/nibabel/dicom/siemens_csa.html). In general, you simply need to detect whether two scans have opposite encoding directions, but note that some tools store rows from top-to-bottom (the way we read lines of text, and the method used by raw DICOM) while others write rows from bottom-to-top (the way we draw a graph, with larger values above lower values on the vertical axis, the default in NIfTI’s forerunner Analyze). Since NIfTI can encode this swap in the S-form, you have to know how your converter copied the rows to solve this. dcm2niix can generate rows in either format depending on the opts.isFlipY flag (which defaults to true, flipping DICOM images to match the Analyze style).


#5

It should be noted that DICOM “COLUMN” and “ROW” do not necessarily correspond with NIfTI dimensions i and j. For example, dcm2nii, dicm2nii and dcm2niix have options to losslessly rotate 3D acquisitions so that they have the closest orthogonal axis to the NIfTI s-form identity matrix (e.g. canonical space). In practice, to my knowledge all converters preserver the Column->i, Row->j for 2D EPI acquisitions. The most popular slice-time correction tools all assume that the images are i*j in plane, and that k refers to different slices.


#6

Hi @Chris_Rorden ,

Many thanks for taking the time to weigh in on this. Your feedback makes sense and is very helpful. For anyone using Python, I’ve started writing a simple function to return the value in question (below) which I’ll update as I go. Also, I’ll see if the AFNI crew can tell me what Dimon is doing behind the scenes in terms of row copying.

import dicom as pydicom
import nibabel.nicom.csareader as csareader

rowcol_to_niftidim = {'COL': 'i', 'ROW': 'j'}
pedp_to_sign = {0: '-', 1: ''} 

def get_bids_phase_encoding_direction(dicom_path):
    """Return BIDS PhaseEncodingDirection string (i, j, k, i-, j-, k-) for DICOM at dicom_path.

    NOTE: work-in-progress
    """ 
    dcm = pydicom.read_file(dicom_path)
    inplane_pe_dir = dcm_pa[int('00181312', 16)].value
    csa_str = dcm[int('00291010', 16)].value
    csa_tr = csareader.read(csa_str)
    pedp = csa_tr['tags']['PhaseEncodingDirectionPositive']['items'][0]
    ij = rowcol_to_niftidim[inplane_pe_dir]
    sign = pedp_to_sign[pedp]
    return '{}{}'.format(ij, sign)

#8

Dear Chris,
I’m a newbee trying to get used to organizing my data in BIDS format, and preprocessing it with fmriprep.
As I am a Philips scanner user,
How can I find the corresponding information, in my DICOM files?
On the scanner, the polarity is described as fatshift direction, in A and P.
I don’t know which is j and j-, respectively.
Thanks in advance for your help and thanks for the great pipeline :smile:


#9

If you recompile the latest version of dcm2niix you will see it will now save ImageOrientationPatientDICOM and InPlanePhaseEncodingDirectionDICOM in the BIDS files. The InPlanePhaseEncodingDirectionDICOM should be either ROW or COL. For axial acquisitions ROW is the L->R dimension and COL is the R->L dimension. For Siemens scanners you can determine ithe polarity of phase encoding by reading the “PhaseEncodingDirection” from the CSA header, but I am not sure the Philips equivalent. I do not have access to Philips data. Presumably, you have sample data acquired in AP and PA phase encoding, so perhaps you can look at the DICOM headers with a tool like Horos and tell me how to discriminate phase encoding direction.


#10

Hi @Chris_Rorden,

I was hoping to resurrect this thread for GE. I can’t spot anything in their dicom conformance statement that distinguishes between two images of opposite polarity:

There’s a couple of promising looking ones but they don’t show up as different in a couple of images that I know to be different (I used AFNI’s dicom_hdr to assess this).

I’ve attached a DTI and EPI technical scan (shared with consent). I wonder could you check them out and see if the polarity is stored in the header.

https://drive.google.com/open?id=1GHr5CjUOk51H1MpnVbKagDnvr5F-t6-J

Thanks,

John


#11

@leej3 you may want to try out the latest dcm2niix pre-release. It does attempt to read the proprietary GE Protocol Data Block that can help decode phase encoding direction and slice timing. The release notes describe the caveats. I do not have GE hardware, so please test and report any issues on the dcm2niix github page.


#12

Excellent. This is fantastic. Thanks. It works on the first one I fed it. I’ll work through some more scans now and report any issues on github.

John