From 23d087566a22edd4f50e4afe829143cb8f6e6720 Mon Sep 17 00:00:00 2001 From: neurolabusc Date: Mon, 20 Dec 2021 13:50:48 -0500 Subject: [PATCH] Siemens XA20 omits echo number (018,0086) (https://github.com/rordenlab/dcm2niix/issues/568) --- console/nii_dicom.cpp | 11 ++++++++++- console/nii_dicom.h | 2 +- console/nii_dicom_batch.cpp | 21 ++++++++++++++------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/console/nii_dicom.cpp b/console/nii_dicom.cpp index 5d3b6a2b..0e08d79a 100644 --- a/console/nii_dicom.cpp +++ b/console/nii_dicom.cpp @@ -777,7 +777,7 @@ struct TDICOMdata clear_dicom_data() { d.zSpacing = 0.0; d.zThick = 0.0; //~ d.numberOfDynamicScans = 0; - d.echoNum = 1; + d.echoNum = 0; d.echoTrainLength = 0; d.waterFatShift = 0.0; d.groupDelay = 0.0; @@ -4266,6 +4266,7 @@ const uint32_t kEffectiveTE = 0x0018 + (0x9082 << 16); #define kSequenceVariant21 0x0021 + (0x105B << 16) //CS #define kPATModeText 0x0021 + (0x1009 << 16) //LO, see kImaPATModeText #define kTimeAfterStart 0x0021 + (0x1104 << 16) //DS +//#define kICE_Dims 0x0021 + (0x1106 << 16) //LO #define kPhaseEncodingDirectionPositiveSiemens 0x0021 + (0x111C << 16) //IS //#define kRealDwellTime 0x0021+(0x1142<< 16 )//IS #define kBandwidthPerPixelPhaseEncode21 0x0021 + (0x1153 << 16) //FD @@ -5772,6 +5773,14 @@ const uint32_t kEffectiveTE = 0x0018 + (0x9082 << 16); //printf("x\t%d\t%g\tkTimeAfterStart\n", acquisitionTimesGE_UIH, d.CSA.sliceTiming[acquisitionTimesGE_UIH]); acquisitionTimesGE_UIH++; break; + /*case kICE_Dims: { //issue568 "X_4_1_1_1_1_160_1_1_1_1_1_277" + if (d.manufacturer != kMANUFACTURER_SIEMENS) + break; + char iceStr[kDICOMStr]; + dcmStr(lLength, &buffer[lPos], iceStr); + printf("do something profound with %s\n", iceStr); + break; + }*/ case kPhaseEncodingDirectionPositiveSiemens: { if (d.manufacturer != kMANUFACTURER_SIEMENS) break; diff --git a/console/nii_dicom.h b/console/nii_dicom.h index ed952a06..c7b2a583 100644 --- a/console/nii_dicom.h +++ b/console/nii_dicom.h @@ -50,7 +50,7 @@ extern "C" { #define kCPUsuf " " //unknown CPU #endif -#define kDCMdate "v1.0.20211215" +#define kDCMdate "v1.0.20211220" #define kDCMvers kDCMdate " " kJP2suf kLSsuf kCCsuf kCPUsuf static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens Mosaic diff --git a/console/nii_dicom_batch.cpp b/console/nii_dicom_batch.cpp index 27081d4f..9834bcb0 100644 --- a/console/nii_dicom_batch.cpp +++ b/console/nii_dicom_batch.cpp @@ -1398,7 +1398,7 @@ tse3d: T2*/ json_Float(fp, "\t\"SAR\": %g,\n", d.SAR); if (d.numberOfAverages > 1.0) json_Float(fp, "\t\"NumberOfAverages\": %g,\n", d.numberOfAverages); - if ((d.echoNum > 1) || (d.isMultiEcho)) + if ((d.echoNum > 1) || ((d.isMultiEcho) && (d.echoNum > 0))) fprintf(fp, "\t\"EchoNumber\": %d,\n", d.echoNum); if ((d.TE > 0.0) && (!d.isXRay)) fprintf(fp, "\t\"EchoTime\": %g,\n", d.TE / 1000.0); @@ -3107,11 +3107,14 @@ int nii_createFilename(struct TDICOMdata dcm, char *niiFilename, struct TDCMopts } // myMultiEchoFilenameSkipEcho1 https://github.com/rordenlab/dcm2niix/issues/237 #ifdef myMultiEchoFilenameSkipEcho1 - if ((isAddNamePostFixes) && (!isEchoReported) && (dcm.isMultiEcho) && (dcm.echoNum >= 1)) { //multiple echoes saved as same series + if ((isAddNamePostFixes) && (!isEchoReported) && (dcm.isMultiEcho)) { //multiple echoes saved as same series #else if ((isAddNamePostFixes) && (!isEchoReported) && ((dcm.isMultiEcho) || (dcm.echoNum > 1))) { //multiple echoes saved as same series #endif - sprintf(newstr, "_e%d", dcm.echoNum); + if ((dcm.echoNum < 1) && (dcm.TE > 0)) + sprintf(newstr, "_e%g", dcm.TE); //issue568: Siemens XA20 might omit echo number + else + sprintf(newstr, "_e%d", dcm.echoNum); strcat(outname, newstr); isEchoReported = true; } @@ -6277,8 +6280,8 @@ int saveDcm2NiiCore(int nConvert, struct TDCMsort dcmSort[], struct TDICOMdata d nii_scale16bitUnsigned(imgM, &hdr0, opts.isVerbose); //allow UINT16 to use full dynamic range } else if ((opts.isMaximize16BitRange == kMaximize16BitRange_False) && (hdr0.datatype == DT_UINT16) && (!dcmList[dcmSort[0].indx].isSigned)) nii_check16bitUnsigned(imgM, &hdr0, opts.isVerbose); //save UINT16 as INT16 if we can do this losslessly - if ((dcmList[dcmSort[0].indx].isXA10A) && (nConvert < 2)) - printWarning("Siemens XA DICOM inadequate for robust conversion (issue 236)\n"); + //if ((dcmList[dcmSort[0].indx].isXA10A) && (nConvert < 2)) //20211220: XA30 appears robust + // printWarning("Siemens XA DICOM inadequate for robust conversion (issue 236)\n"); if ((dcmList[dcmSort[0].indx].isXA10A) && (nConvert > 1)) printWarning("Siemens XA exported as classic not enhanced DICOM (issue 236)\n"); printMessage("Convert %d DICOM as %s (%dx%dx%dx%d)\n", nConvert, pathoutname, hdr0.dim[1], hdr0.dim[2], hdr0.dim[3], hdr0.dim[4]); @@ -6803,8 +6806,12 @@ bool isSameSet(struct TDICOMdata d1, struct TDICOMdata d2, struct TDCMopts *opts if ((!(isSameFloat(d1.TE, d2.TE))) || (d1.echoNum != d2.echoNum)) { if ((!warnings->echoVaries) && (d1.isXRay)) //for CT/XRay we check DICOM tag 0018,1152 (XRayExposure) printMessage("Slices not stacked: X-Ray Exposure varies (exposure %g, %g; number %d, %d). Use 'merge 2D slices' option to force stacking\n", d1.TE, d2.TE, d1.echoNum, d2.echoNum); - if ((!warnings->echoVaries) && (!d1.isXRay)) //for MRI - printMessage("Slices not stacked: echo varies (TE %g, %g; echo %d, %d). Use 'merge 2D slices' option to force stacking\n", d1.TE, d2.TE, d1.echoNum, d2.echoNum); + if ((!warnings->echoVaries) && (!d1.isXRay)) {//for MRI + if (d1.echoNum == d2.echoNum) + printMessage("Slices not stacked: echo varies (TE %g, %g). No echo number (0018,0086; issue 568). Use 'merge 2D slices' option to force stacking\n", d1.TE, d2.TE); + else + printMessage("Slices not stacked: echo varies (TE %g, %g; echo %d, %d). Use 'merge 2D slices' option to force stacking\n", d1.TE, d2.TE, d1.echoNum, d2.echoNum); + } warnings->echoVaries = true; *isMultiEcho = true; return false;