rordenlab / dcm2niix

dcm2nii DICOM to NIfTI converter: compiled versions available from NITRC
https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage
Other
895 stars 228 forks source link

GE AcquisitionDuration #808

Closed mr-jaemin closed 7 months ago

mr-jaemin commented 7 months ago

GE private DICOM tag (0019,105a) Acquisition Duration reports the duration of acquisition in micro-seconds, i.e. scan time for the series. I found that this information is useful.

I think that this tag is similar to DICOM 0018,9073 is BIDS AcquisitionDuration captupred #606

I tested this tag using Open MRI Consistency Data (specifically, Phantom02_DICOM.tar) and found that it matched with the console scan time for all series (localizer, t1 MPRAGE, fMRI, B0map, DTI)

For example, Sag_MPRAGE_T1

(0019,105a) FL 3.0118515e+08                            #   4, 1 AcquisitionDuration

--> 301.185 seconds --> 05:01 (5 min 1 sec)

image

Console viewer (red arrow ) annotates the scan time in the 05:01 format

Screenshot 2024-03-27 at 11 34 16 PM

I would propose to populate these from GE (0019,105a) Acquisition Duration

"AcquisitionDuration": 301.185,
"AcquisitionDurationGE": "05:01",

Here are additional examples from Phantom02_DICOM.tar using a local commit:

02_Plane_Localizer.json:    "AcquisitionDurationGE": "00:17",
03_Sag_MPRAGE_T1.json:  "AcquisitionDurationGE": "05:01",
04_Standard_fBIRN_QA.json:  "AcquisitionDurationGE": "06:40",
05_rsfMRI_fieldmap_PE0.json:    "AcquisitionDurationGE": "00:15",
06_rsfMRI_fieldmap_PE1.json:    "AcquisitionDurationGE": "00:15",
07_3dB0map_rsfMRI_fieldmaphz.json:  "AcquisitionDurationGE": "01:00",
07_3dB0map_rsfMRI.json: "AcquisitionDurationGE": "01:00",
08_rsfMRI_Run.json: "AcquisitionDurationGE": "05:13",
09_DTI_PE1.json:    "AcquisitionDurationGE": "01:04",
10_3dB0map_fieldmaphz.json: "AcquisitionDurationGE": "01:38",
10_3dB0map.json:    "AcquisitionDurationGE": "01:38",
11_DTI.json:    "AcquisitionDurationGE": "12:26",
12_3dB0map_fieldmaphz.json: "AcquisitionDurationGE": "01:38",
12_3dB0map.json:    "AcquisitionDurationGE": "01:38",

02_Plane_Localizer.json:    "AcquisitionDuration": 17.2842,
03_Sag_MPRAGE_T1.json:  "AcquisitionDuration": 301.185,
04_Standard_fBIRN_QA.json:  "AcquisitionDuration": 400,
05_rsfMRI_fieldmap_PE0.json:    "AcquisitionDuration": 14.8,
06_rsfMRI_fieldmap_PE1.json:    "AcquisitionDuration": 14.8,
07_3dB0map_rsfMRI_fieldmaphz.json:  "AcquisitionDuration": 60.3984,
07_3dB0map_rsfMRI.json: "AcquisitionDuration": 60.3984,
08_rsfMRI_Run.json: "AcquisitionDuration": 312.8,
09_DTI_PE1.json:    "AcquisitionDuration": 63.9,
10_3dB0map_fieldmaphz.json: "AcquisitionDuration": 97.9132,
10_3dB0map.json:    "AcquisitionDuration": 97.9132,
11_DTI.json:    "AcquisitionDuration": 745.5
12_3dB0map_fieldmaphz.json: "AcquisitionDuration": 97.9132,
12_3dB0map.json:    "AcquisitionDuration": 97.9132,
mr-jaemin commented 7 months ago

Please @neurolabusc review the proposal or the above commit. I will submit the PR once you gives okay.

neurolabusc commented 7 months ago

@mr-jaemin I have two minor comments.

First, your premise is that the private tag 0019,105A is more accurate than the public tag 0018,9073. Therefore, I would ensure that the private tag always gets precedence. While tags are typically provided sequentially, this may not be the case for nested details. Therefore, I would change nii_dicom.cpp:

        case kAcquisitionDuration:
            if (!isSameFloatGE(d.acquisitionDuration, 0.0))
                break; //issue 808: give precedence to more precise measures
            //n.b. used differently by different vendors https://github.com/rordenlab/dcm2niix/issues/225
            d.acquisitionDuration = dcmFloatDouble(lLength, &buffer[lPos], d.isLittleEndian);
            break;

Second, I would not add the AcquisitionDurationGE field to nii_dicom_batch.cpp as it is completely redundant with AcquisitionDuration (though rounded so it stores precision).

If you implement my second comment, you will delete the sprintf() call from your pull request. I recognize that your usage of sprintf is safe, but please use snprintf() instead to remove distracting clang/LLVM compiler warnings. Specifically, clang will report warning: 'sprintf' is deprecated: This function is provided for compatibility reasons only. Due to security concerns inherent in the design of sprintf(3), it is highly recommended that you use snprintf(3) instead. While @yhuang43 and the FreeSurfer team have added a few sprintf() calls, they all require the USING_DCM2NIIXFSWRAPPER compilation flag and therefore do not impact the regular compilation.

mr-jaemin commented 7 months ago

@neurolabusc Thanks for your comments.

brice82 commented 7 months ago

Hi @neurolabusc and @mr-jaemin,

If I may make a little suggestions, even though this is nice have this field in a human readable format, it is maybe not desired in every situation (and this is very GEHC specific).

As there is already some specific fields enable only when a certain compilation flag is enabled, maybe we can create a GEHC specific compile flag.

for example in https://github.com/rordenlab/dcm2niix/blob/e2ead4b3c3b6d9763ca17638c10e3b407bf3f21d/console/nii_dicom_batch.cpp#L2135
There is MY_DEBUG flag for some GEHC specific parameters. Maybe, we could make a compile flag like GEHC_EXTRA_FIELD_FLAG to have in addition AcquisitionDurationGE, and also the already existing fields lke EchoSpacingMicroSecondsGE , NotPhysicalNumberOfAcquiredPELinesGE and NotPhysicalTotalReadOutTimeGE.

What do you think ? what that be reasonable ?

neurolabusc commented 7 months ago

My sense is to add these features to all version of dcm2niix, so different users do not get different details. I do think that we should not included redundant tags where they include the same informatin (AcquisitionDuration vs AcquisitionDurationGE), we should use private tags when they provide more precise information than public tags (0019,105A vs 0018,9073), and we should include sequence details in the JSON files if they may aid subsequent processing (EchoSpacingMicroSecondsGE , NotPhysicalNumberOfAcquiredPELinesGE and NotPhysicalTotalReadOutTimeGE). Happy to meet and build consensus if there is disagreement on these thoughts.

mr-jaemin commented 7 months ago

Agreed. Since both DICOM and BIDS AcquisitionDuration are in seconds, I would remove a redundant AcquisitionDurationGE (MM:SS) tag.

submitted PR #810

In summary,