Skip to content

Commit

Permalink
Experimental solution for issue 384 (#384)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Mar 16, 2020
1 parent 6040de5 commit 616d0be
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 15 deletions.
2 changes: 1 addition & 1 deletion FILENAMING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ In general dcm2niix creates images with 3D dimensions, or 4 dimensions when the
- _MoCo is appended to the ProtocolName if Image Type (0008,0008) includes the term 'MOCO'. This helps disambiguate Siemens fMRI runs where both motion corrected and raw data is stored for a single session.
- _real real component of complex image
- _phMag rare case where phase and magnitude are saved as the 4th dimension
- _t If the trigger delay time (0020,9153) is non-zero, it will be recorded in the file name. For example, the files "T1_t178.nii" and "T1_t511" suggests that the T1 scan was acquired with two cardiac trigger delays (178 and 511ms after the last R-peak).
- _t If the trigger delay time (0020,9153) or trigger time (0018,1060) is non-zero, it will be recorded in the file name. For example, the files "T1_t178.nii" and "T1_t511" suggests that the T1 scan was acquired with two cardiac trigger delays (178 and 511ms after the last R-peak).
- _Tilt is specific to [CT scans](https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage#Computed_Tomography_.28CT.2C_CAT.29). These scans can be acquired with a gantry tilt that causes a skew that can not be stored in a NIfTI qForm. Therefore, the slices are resampled to remove the effect of tilt.

Some post-fixes are specific to Philips DICOMs
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ The following tools exploit dcm2niix
- [brainnetome DiffusionKit](http://diffusion.brainnetome.org/en/latest/) uses dcm2niix to convert images.
- [Brain imAgiNg Analysis iN Arcana (Banana)](https://pypi.org/project/banana/) is a collection of brain imaging analysis workflows, it uses dcm2niix for format conversions.
- [BOLD5000_autoencoder](https://github.com/nmningmei/BOLD5000_autoencoder) uses dcm2niix to pipe imaging data into an unsupervised machine learning algorithm.
- [clinica](https://github.com/aramis-lab/clinica) is a software platform for clinical neuroimaging studies that uses dcm2niix to convert DICOM images.
- [dcm2niix can help convert data from the Adolescent Brain Cognitive Development (ABCD) DICOM to BIDS](https://github.com/ABCD-STUDY/abcd-dicom2bids)
- [bidsify](https://github.com/spinoza-rec/bidsify) is a Python project that uses dcm2niix to convert DICOM and Philips PAR/REC images to the BIDS standard.
- [bidskit](https://github.com/jmtyszka/bidskit) uses dcm2niix to create [BIDS](http://bids.neuroimaging.io/) datasets.
Expand All @@ -139,6 +140,7 @@ The following tools exploit dcm2niix
- [fsleyes](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FSLeyes) is a powerful Python-based image viewer. It uses dcm2niix to handle DICOM files through its fslpy libraries.
- [Functional Real-Time Interactive Endogenous Neuromodulation and Decoding (FRIEND) Engine](https://github.com/InstitutoDOr/FriendENGINE) uses dcm2niix.
- [heudiconv](https://github.com/nipy/heudiconv) can use dcm2niix to create [BIDS](http://bids.neuroimaging.io/) datasets.
- [kipettools](https://github.com/mathesong/kipettools) uses dcm2niix to load PET data.
- [LEAD-DBS](http://www.lead-dbs.org/) uses dcm2niix for [DICOM import](https://github.com/leaddbs/leaddbs/blob/master/ea_dicom_import.m).
- [MRIcroGL](https://github.com/neurolabusc/MRIcroGL) is available for MacOS, Linux and Windows and provides a graphical interface for dcm2niix. You can get compiled copies from the [MRIcroGL NITRC web site](https://www.nitrc.org/projects/mricrogl/).
- [neurodocker](https://github.com/kaczmarj/neurodocker) includes dcm2niix as a lean, minimal install Dockerfile.
Expand All @@ -147,7 +149,7 @@ The following tools exploit dcm2niix
- [neurodocker](https://github.com/kaczmarj/neurodocker) generates [custom](https://github.com/rordenlab/dcm2niix/issues/138) Dockerfiles given specific versions of neuroimaging software.
- [NeuroElf](http://neuroelf.net) can use dcm2niix to convert DICOM images.
- [Neuroinformatics Database (NiDB)](https://github.com/gbook/nidb) is designed to store, retrieve, analyze, and share neuroimaging data. It uses dcm2niix for image QA and handling some formats.
- [NiftyPET](https://niftypet.readthedocs.io/en/latest/intro.htmlNiftyPET) provides PET image reconstruction and analysis, and uses dcm2niix to handle DICOM images.
- [NiftyPET](https://niftypet.readthedocs.io/en/latest/install.html) provides PET image reconstruction and analysis, and uses dcm2niix to handle DICOM images.
- [nipype](https://github.com/nipy/nipype) can use dcm2niix to convert images.
- [PNL-nipype](https://github.com/pnlbwh/Dummy-PNL-nipype) is a Python script that can convert dcm2niix created NIfTI files to the popular NRRD format (including DWI gradient tables). Note, recent versions of dcm2niix can directly convert DICOM images to NRRD.
- [pydcm2niix is a Python module for working with dcm2niix](https://github.com/jstutters/pydcm2niix).
Expand Down
2 changes: 1 addition & 1 deletion console/main_console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ void showHelp(const char * argv[], struct TDCMopts opts) {
#if !defined(_WIN64) && !defined(_WIN32) //shell script for Unix only
printf(" -u : up-to-date check\n");
#endif
printf(" -v : verbose (n/y or 0/1/2 [no, yes, logorrheic], default 0)\n");
printf(" -v : verbose (n/y or 0/1/2, default 0) [no, yes, logorrheic]\n");
//#define kNAME_CONFLICT_SKIP 0 //0 = write nothing for a file that exists with desired name
//#define kNAME_CONFLICT_OVERWRITE 1 //1 = overwrite existing file with same name
//#define kNAME_CONFLICT_ADD_SUFFIX 2 //default 2 = write with new suffix as a new file
Expand Down
22 changes: 14 additions & 8 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4350,6 +4350,7 @@ uint32_t kSequenceDelimitationItemTag = 0xFFFE +(0xE0DD << 16 );
double TE = 0.0; //most recent echo time recorded
bool is2005140FSQ = false;
bool isDICOMANON = false; //issue383
bool isMATLAB = false; //issue383
//double contentTime = 0.0;
int echoTrainLengthPhil = 0;
int philMRImageDiffBValueNumber = 0;
Expand Down Expand Up @@ -4873,10 +4874,11 @@ double TE = 0.0; //most recent echo time recorded
char impTxt[kDICOMStr];
dcmStr (lLength, &buffer[lPos], impTxt);
int slen = (int) strlen(impTxt);
//if ((slen > 5) && (strstr(impTxt, "dcm4che") != NULL) )
// isDcm4Che = true;
if ((slen > 5) && (strstr(impTxt, "MATLAB") != NULL) )
isMATLAB = true;
if((slen < 5) || (strstr(impTxt, "XA10A") == NULL) ) break;
d.isXA10A = true;

break; }
case kSourceApplicationEntityTitle: {
char saeTxt[kDICOMStr];
Expand Down Expand Up @@ -5148,16 +5150,19 @@ double TE = 0.0; //most recent echo time recorded
break; }
case kInversionTimes : {//issue 380
if ((lLength < 8) || ((lLength % 8) != 0)) break;
int nTI = lLength / 8;
d.TI = dcmFloatDouble(lLength, &buffer[lPos], d.isLittleEndian);
/*
//see issue385 : Philips reports Implausible InversionTimes
int nTI = lLength / 8;
if (nTI > 1) {
bool isTIvaries = false;
for (int i = 1; i < nTI; i++) {
float ti = dcmFloatDouble(8, &buffer[lPos+(i*8)],d.isLittleEndian);
if (!isSameFloatGE(ti, d.TI)) isTIvaries = true;
}
if (isTIvaries) printWarning("0018,9079 reports multiple inversion times.\n");
if (isTIvaries) printWarning("0018,9079 reports multiple inversion times: %s\n", fname);
}
*/
break; }
case kPartialFourier : //(0018,9081) CS [YES],[NO]
if (lLength < 2) break;
Expand Down Expand Up @@ -5539,15 +5544,16 @@ double TE = 0.0; //most recent echo time recorded
case kImagingFrequency :
d.imagingFrequency = dcmStrFloat(lLength, &buffer[lPos]);
break;
case kTriggerTime:
case kTriggerTime: {
//untested method to detect slice timing for GE PSD “epi” with multiphase option
// will not work for current PSD “epiRT” (BrainWave RT, fMRI/DTI package provided by Medical Numerics)
if (d.manufacturer != kMANUFACTURER_GE) break;
if ((d.manufacturer != kMANUFACTURER_GE) && (d.manufacturer != kMANUFACTURER_PHILIPS)) break; //issue384
d.triggerDelayTime = dcmStrFloat(lLength, &buffer[lPos]); //???? issue 336
if (d.manufacturer != kMANUFACTURER_GE) break;
d.CSA.sliceTiming[acquisitionTimesGE_UIH] = d.triggerDelayTime;
//printf("%g\n", d.CSA.sliceTiming[acquisitionTimesGE_UIH]);
acquisitionTimesGE_UIH ++;
break;
break; }
case kEffectiveTE : {
TE = dcmFloatDouble(lLength, &buffer[lPos], d.isLittleEndian);
if (d.TE <= 0.0)
Expand Down Expand Up @@ -6721,7 +6727,7 @@ if (d.isHasPhase)
strcpy(d.seriesInstanceUID, d.studyInstanceUID);
d.seriesUidCrc = mz_crc32X((unsigned char*) &d.protocolName, strlen(d.protocolName));
}
if (isDICOMANON) {
if ((isDICOMANON) && (isMATLAB)) {
//issue 383
d.seriesInstanceUID[0] = '\0';
strcat(d.seriesInstanceUID, d.studyDate);
Expand Down
16 changes: 12 additions & 4 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ tse3d: T2*/
json_Str(fp, "\t\"ReceiveCoilActiveElements\": \"%s\",\n", d.coilElements);
if (strcmp(d.coilElements,d.coilName) != 0)
json_Str(fp, "\t\"CoilString\": \"%s\",\n", d.coilName);
if ((!d.is3DAcq) && (d.phaseEncodingLines > d.echoTrainLength) && (d.echoTrainLength > 1)) {
if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (!d.is3DAcq) && (d.phaseEncodingLines > d.echoTrainLength) && (d.echoTrainLength > 1)) {
//ETL is > 1, as some GE files list 1, as an example see series mr_0005 in dcm_qa_nih
float pf = (float)d.phaseEncodingLines;
if (d.accelFactPE > 1)
Expand Down Expand Up @@ -2451,7 +2451,7 @@ int nii_createFilename(struct TDICOMdata dcm, char * niiFilename, struct TDCMopt
sprintf(newstr, "_t%d", (int)roundf(dcm.triggerDelayTime));
strcat (outname,newstr);
}
//could add (isAddNamePostFixes) to these next two, but consequences could be catastrophic
//could add (isAddNamePostFixes) to these next two, but consequences could be catastrophic
if (dcm.isRawDataStorage) //avoid name clash for Philips XX_ files
strcat (outname,"_Raw");
if (dcm.isGrayscaleSoftcopyPresentationState) //avoid name clash for Philips PS_ files
Expand Down Expand Up @@ -4634,7 +4634,8 @@ int saveDcm2NiiCore(int nConvert, struct TDCMsort dcmSort[],struct TDICOMdata dc
if (nConvert > 1) {
//next: detect trigger time see example https://www.slicer.org/wiki/Documentation/4.4/Modules/MultiVolumeExplorer
double triggerDx = dcmList[dcmSort[nConvert-1].indx].triggerDelayTime - dcmList[indx0].triggerDelayTime;
dcmList[indx0].triggerDelayTime = triggerDx;
if (triggerDx > 0.0) //issue 384
dcmList[indx0].triggerDelayTime = triggerDx;
//next: determine gantry tilt
if (dcmList[indx0].gantryTilt != 0.0f)
printWarning("Note these images have gantry tilt of %g degrees (manufacturer ID = %d)\n", dcmList[indx0].gantryTilt, dcmList[indx0].manufacturer);
Expand Down Expand Up @@ -5365,7 +5366,7 @@ int isSameFloatDouble (double a, double b) {
}

struct TWarnings { //generate a warning only once per set
bool acqNumVaries, bitDepthVaries, dateTimeVaries, echoVaries, phaseVaries, coilVaries, forceStackSeries, seriesUidVaries, nameVaries, nameEmpty, orientVaries;
bool acqNumVaries, bitDepthVaries, dateTimeVaries, echoVaries, triggerVaries, phaseVaries, coilVaries, forceStackSeries, seriesUidVaries, nameVaries, nameEmpty, orientVaries;
};

TWarnings setWarnings() {
Expand All @@ -5375,6 +5376,7 @@ TWarnings setWarnings() {
r.dateTimeVaries = false;
r.phaseVaries = false;
r.echoVaries = false;
r.triggerVaries = false;
r.coilVaries = false;
r.seriesUidVaries = false;
r.forceStackSeries = false;
Expand Down Expand Up @@ -5463,6 +5465,12 @@ bool isSameSet (struct TDICOMdata d1, struct TDICOMdata d2, struct TDCMopts* opt
*isMultiEcho = true;
return false;
}
if ((d1.triggerDelayTime != d2.triggerDelayTime) && (d1.manufacturer == kMANUFACTURER_PHILIPS)) { //issue 384
if (!warnings->triggerVaries)
printMessage("Slices not stacked: trigger time varies\n");
warnings->triggerVaries = true;
return false;
}
if (d1.coilCrc != d2.coilCrc) {
if (!warnings->coilVaries)
printMessage("Slices not stacked: coil varies\n");
Expand Down

0 comments on commit 616d0be

Please sign in to comment.