From c5caaa9f858b704b61d3ff4a7989282922dd712e Mon Sep 17 00:00:00 2001 From: neurolabusc Date: Tue, 12 Sep 2023 12:17:50 -0400 Subject: [PATCH] Improve BIDS guess (https://github.com/rordenlab/dcm2niix/issues/753) --- BIDS/README.md | 8 ++++++-- console/nii_dicom_batch.cpp | 34 ++++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/BIDS/README.md b/BIDS/README.md index 37200c58..c48d5a43 100644 --- a/BIDS/README.md +++ b/BIDS/README.md @@ -263,7 +263,7 @@ Note that [many of the fields listed by BIDS](https://bids-specification.readthe |---------------------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------| | ArterialSpinLabelingType | | `PASL` or `PCASL` | B | | LabelOffset | | 2D pCASL [ep2d_pcasl](http://www.loft-lab.org) | D | -| PostLabelDelay | s | 2D pCASL [ep2d_pcasl](http://www.loft-lab.org), [FAIREST](https://pubmed.ncbi.nlm.nih.gov/11746944/) (`ep2d_fairest`) | D | +| PostLabelingDelay | s | 2D pCASL [ep2d_pcasl](http://www.loft-lab.org), [FAIREST](https://pubmed.ncbi.nlm.nih.gov/11746944/) (`ep2d_fairest`) | B | | PostInversionDelay | s | 2D [FAIREST](https://pubmed.ncbi.nlm.nih.gov/11746944/) (`ep2d_fairest`) | D | | NumRFBlocks | | 2D pCASL [ep2d_pcasl](http://www.loft-lab.org) | D | | RFGap | | 2,3D pCASL [ep2d_pcasl, tgse_pcasl](http://www.loft-lab.org) | D | @@ -334,7 +334,7 @@ Fields specific to [Siemens XA-series](https://github.com/rordenlab/dcm2niix/tre | ReceiveCoilActiveElements | | DICOM tag 0021,114F | B | | BandwidthPerPixelPhaseEncode | Hz | DICOM tag 0021,1153 | D | | ScanningSequence | | DICOM tag 0021,105a | D | -| PostLabelDelay | s | DICOM tag 0018,9258 | D | +| PostLabelingDelay | s | DICOM tag 0018,9258 | B | | NonlinearGradientCorrection | b | 0008,0008 or 0021,1175 | B | | PhaseEncodingDirection | | polarity from 0021,111c | B | | SpoilingState | | 0021,105B | B | @@ -349,3 +349,7 @@ Fields specific to United Imaging Healthcare systems (e.g. uMR 770). |--------------------------------|------|--------------------------|------------| | BandwidthPerPixelPhaseEncode | Hz | DICOM tag 0019,1028 | B | | ParallelReductionFactorInPlane | | DICOM tag 0065,100D | B | + +### Notes + + - Prior to v1.0.20230411, dcm2niix created the internal tag `PostLabelDelay`, subsequent versions use the newly introduced BIDS tag `PostLabelingDelay` \ No newline at end of file diff --git a/console/nii_dicom_batch.cpp b/console/nii_dicom_batch.cpp index ab925e55..6c8d32c2 100644 --- a/console/nii_dicom_batch.cpp +++ b/console/nii_dicom_batch.cpp @@ -1649,12 +1649,16 @@ tse3d: T2*/ json_FloatNotNan(fp, "\t\"LabelingDuration\": %g,\n", csaAscii.ulLabelingDuration * (1.0 / 1000000.0)); //usec->sec json_FloatNotNan(fp, "\t\"PostLabelingDelay\": %g,\n", csaAscii.sPostLabelingDelay * (1.0 / 1000000.0)); //usec -> sec } + //ASL specific tags - 2D pCASL Danny J.J. Wang http://www.loft-lab.org if ((strstr(pulseSequenceDetails, "ep2d_pcasl")) || (strstr(pulseSequenceDetails, "ep2d_pcasl_UI_PHC"))) { isPCASL = true; repetitionTimePreparation = d.TR; json_FloatNotNan(fp, "\t\"LabelOffset\": %g,\n", csaAscii.adFree[1]); //mm - json_FloatNotNan(fp, "\t\"PostLabelDelay\": %g,\n", csaAscii.adFree[2] * (1.0 / 1000000.0)); //usec -> sec - json_FloatNotNan(fp, "\t\"NumRFBlocks\": %g,\n", csaAscii.adFree[3]); + json_FloatNotNan(fp, "\t\"PostLabelingDelay\": %g,\n", csaAscii.adFree[2] * (1.0 / 1000000.0)); //usec -> sec + float num_RF_Block = csaAscii.adFree[3]; + json_FloatNotNan(fp, "\t\"NumRFBlocks\": %g,\n", num_RF_Block); + // Sep 5, 2023, at 7:56 PM, Danny JJ Wang the labeling duration is (0.92*20*Num_RF_Block) ms + json_FloatNotNan(fp, "\t\"LabelingDuration\": %g,\n", (0.92 *20.0 *num_RF_Block)/1000.0); //in seconds json_FloatNotNan(fp, "\t\"RFGap\": %g,\n", csaAscii.adFree[4] * (1.0 / 1000000.0)); //usec -> sec json_FloatNotNan(fp, "\t\"MeanGzx10\": %g,\n", csaAscii.adFree[10]); json_FloatNotNan(fp, "\t\"PhiAdjust\": %g,\n", csaAscii.adFree[11]); // percent @@ -1666,6 +1670,10 @@ tse3d: T2*/ json_FloatNotNan(fp, "\t\"RFGap\": %g,\n", csaAscii.adFree[4] * (1.0 / 1000000.0)); //usec -> sec json_FloatNotNan(fp, "\t\"MeanGzx10\": %g,\n", csaAscii.adFree[10]); // mT/m json_FloatNotNan(fp, "\t\"T1\": %g,\n", csaAscii.adFree[12] * (1.0 / 1000000.0)); //usec -> sec + float num_RF_Block = csaAscii.adFree[3]; + json_FloatNotNan(fp, "\t\"NumRFBlocks\": %g,\n", num_RF_Block); + // Sep 5, 2023, at 7:56 PM, Danny JJ Wang the labeling duration is (0.92*20*Num_RF_Block) ms + json_FloatNotNan(fp, "\t\"LabelingDuration\": %g,\n", (0.92 *20.0 *num_RF_Block)/1000.0); //in seconds } //ASL specific tags - 2D PASL Siemens Product if (strstr(pulseSequenceDetails, "ep2d_pasl")) { @@ -1684,7 +1692,7 @@ tse3d: T2*/ if (strstr(pulseSequenceDetails, "ep2d_fairest")) { isPASL = true; json_FloatNotNan(fp, "\t\"PostInversionDelay\": %g,\n", csaAscii.adFree[2] * (1.0 / 1000.0)); //usec->sec - json_FloatNotNan(fp, "\t\"PostLabelDelay\": %g,\n", csaAscii.adFree[4] * (1.0 / 1000.0)); //usec -> sec + json_FloatNotNan(fp, "\t\"PostLabelingDelay\": %g,\n", csaAscii.adFree[4] * (1.0 / 1000.0)); //usec -> sec } //ASL specific tags - Oxford (Thomas OKell) bool isOxfordASL = false; @@ -1917,7 +1925,7 @@ tse3d: T2*/ */ //generic public ASL tags if (d.postLabelDelay > 0) - json_Float(fp, "\t\"PostLabelDelay\": %g,\n", float(d.postLabelDelay) / 1000.0); + json_Float(fp, "\t\"PostLabelingDelay\": %g,\n", float(d.postLabelDelay) / 1000.0); //ASL BIDS tags if ((d.aslFlags & kASL_FLAG_GE_CONTINUOUS) || (d.aslFlags & kASL_FLAG_GE_3DCASL)) fprintf(fp, "\t\"ArterialSpinLabelingType\": \"CASL\",\n"); @@ -1927,7 +1935,7 @@ tse3d: T2*/ fprintf(fp, "\t\"ArterialSpinLabelingType\": \"PASL\",\n"); if (d.durationLabelPulseGE > 0) { json_Float(fp, "\t\"LabelingDuration\": %g,\n", d.durationLabelPulseGE / 1000.0); - json_Float(fp, "\t\"PostLabelDelay\": %g,\n", d.TI / 1000.0); //For GE ASL: InversionTime -> Post-label delay + json_Float(fp, "\t\"PostLabelingDelay\": %g,\n", d.TI / 1000.0); //For GE ASL: InversionTime -> Post-label delay json_Float(fp, "\t\"NumberOfPointsPerArm\": %g,\n", d.numberOfPointsPerArm); json_Float(fp, "\t\"NumberOfArms\": %g,\n", d.numberOfArms); } @@ -6482,6 +6490,8 @@ void setBidsSiemens(struct TDICOMdata *d, int nConvert, int isVerbose, const cha bool isDerived = d->isDerived; //report phase encoding direction bool isDirLabel = false; bool isPart = false; + if (d->isHasPhase) + isPart = true; bool isAddSeriesToRun = true; //except phasemap, where phasediff and magnitude have different series numbers but must share acq char seqName[kDICOMStrLarge]; strcpy(seqName, d->sequenceName); @@ -6569,6 +6579,7 @@ void setBidsSiemens(struct TDICOMdata *d, int nConvert, int isVerbose, const cha } else if ((strstr(seqDetails, "gre_field_mapping") != NULL)) { //prog_fmap isReportEcho = false; //echo encoded in "_magnitude" isAddSeriesToRun = false; + isPart = false; strcpy(dataTypeBIDS, "fmap"); if (d->isHasPhase) strcpy(modalityBIDS, "phasediff"); @@ -6608,18 +6619,17 @@ void setBidsSiemens(struct TDICOMdata *d, int nConvert, int isVerbose, const cha } else if ((strstr(seqDetails, "AALScout") != NULL) || (strstr(seqDetails, "haste") != NULL)) { //localizer: unused strcpy(dataTypeBIDS, "discard"); strcpy(modalityBIDS, "localizer"); - } else if ((strstr(seqDetails, "_bold") != NULL) || (strstr(seqDetails, "pace") != NULL)){ //prog_bold + } else if ((strstr(seqDetails, "_bold")) || (strstr(seqDetails, "pace")) + || (strstr(d->imageType, "FMRI")) || (strstr(seqDetails, "ep2d_fid"))) { //prog_bold //n.b. "Space" is not "pace" strcpy(dataTypeBIDS, "func"); strcpy(modalityBIDS, "bold"); isDirLabel = true; + char* p = strstr(d->protocolName, "func_"); + if (p == d->protocolName) + //todo issue753 infer task from d->protocolName if (strstr(d->seriesDescription, "_SBRef") != NULL) strcpy(modalityBIDS, "sbref"); - } else if ((strstr(d->imageType, "FMRI") != NULL) || (strstr(seqDetails, "ep2d_fid") != NULL)) { - //Hail mary: one Skyra XA30 ADNI rsfMRI_LR 20230109 has no CSA - strcpy(dataTypeBIDS, "func"); - strcpy(modalityBIDS, "bold"); - isDirLabel = true; } else if (strstr(d->sequenceName, "*epse2d") != NULL) { //pepolar? strcpy(dataTypeBIDS, "fmap"); @@ -6848,7 +6858,7 @@ void setBidsPhilips(struct TDICOMdata *d, int nConvert, int isVerbose) { d->pulseSequenceName, d->scanningSequence, d->sequenceVariant); if (isDerived) strcpy(dataTypeBIDS, "derived"); -} //setBidsPhilips +} //setBidsPhilips() void setBidsGE(struct TDICOMdata *d, int nConvert, int isVerbose, const char *filename) { char seqName[kDICOMStrLarge] = "";