From c014f251086c8b368a7e91966dcdc4ffbd969a22 Mon Sep 17 00:00:00 2001 From: Chris Rorden Date: Sat, 27 Oct 2018 17:09:31 -0400 Subject: [PATCH] Update dcm_qa_nih submodule. --- README.md | 7 +++---- console/nii_dicom.cpp | 29 +++++++++++++++++++++++++++++ console/nii_dicom_batch.cpp | 19 ++++++++++--------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 5e7a917d..57ef8b50 100644 --- a/README.md +++ b/README.md @@ -74,16 +74,15 @@ If you have any problems with the cmake build script described above or want to ## Alternatives - - [Valerio Luccio's dinifti](http://cbi.nyu.edu/software/dinifti.php) is focused on conversion of Siemens data. + - [dinifti](http://cbi.nyu.edu/software/dinifti.php) is focused on conversion of Siemens data. - [dcm2nii](http://www.mccauslandcenter.sc.edu/mricro/mricron/dcm2nii.htm) is the predecessor of dcm2niix. It is deprecated for modern images, but does handle image formats that predate DICOM (proprietary Elscint, GE and Siemens formats). - [DWIConvert](https://github.com/BRAINSia/BRAINSTools/tree/master/DWIConvert) converts DICOM images to NRRD and NIfTI formats. - - [Xiangrui Li's dicm2nii](http://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter) is written in Matlab. The Matlab language makes this very scriptable. + - [dicm2nii](http://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter) is written in Matlab. The Matlab language makes this very scriptable. - [dicom2nifti](https://github.com/icometrix/dicom2nifti) uses the scriptable Python wrapper utilizes the [high performance GDCMCONV](http://gdcm.sourceforge.net/wiki/index.php/Gdcmconv) executables. - [MRtrix mrconvert](http://mrtrix.readthedocs.io/en/latest/reference/commands/mrconvert.html) is a useful general purpose image converter and handles DTI data well. It is an outstanding tool for modern Philips enhanced images. - - [Jolinda Smith's mcverter](http://lcni.uoregon.edu/%7Ejolinda/MRIConvert/) has great support for various vendors. + - [mcverter](http://lcni.uoregon.edu/%7Ejolinda/MRIConvert/) has great support for various vendors. - [mri_convert](https://surfer.nmr.mgh.harvard.edu/pub/docs/html/mri_convert.help.xml.html) is part of the popular FreeSurfer package. In my limited experience this tool works well for GE and Siemens data, but fails with Philips 4D datasets. - [SPM12](http://www.fil.ion.ucl.ac.uk/spm/software/spm12/) is one of the most popular tools in the field. It includes DICOM to NIfTI conversion. Being based on Matlab it is easy to script. - - [R2A_GUI](http://r2agui.sourceforge.net/) is a Matlab script that converts Philips PAR/REC images to NIfTI. ## Links diff --git a/console/nii_dicom.cpp b/console/nii_dicom.cpp index d38e4791..e13ff279 100644 --- a/console/nii_dicom.cpp +++ b/console/nii_dicom.cpp @@ -819,6 +819,26 @@ struct TDICOMdata clear_dicom_data() { return d; } //clear_dicom_data() +int isdigitdot(int c) { //returns true if digit or '.' + if (c == '.') return 1; + return isdigit(c); +} + +void dcmStrDigitsDotOnlyKey(char key, char* lStr) { + //e.g. string "F:2.50" returns 2.50 if key==":" + size_t len = strlen(lStr); + if (len < 1) return; + bool isKey = false; + for (int i = 0; i < (int) len; i++) { + if (!isdigitdot(lStr[i]) ) { + isKey = (lStr[i] == key); + lStr[i] = ' '; + + } else if (!isKey) + lStr[i] = ' '; + } +} //dcmStrDigitsOnlyKey() + void dcmStrDigitsOnlyKey(char key, char* lStr) { //e.g. string "p2s3" returns 2 if key=="p" and 3 if key=="s" size_t len = strlen(lStr); @@ -3966,6 +3986,7 @@ const uint32_t kEffectiveTE = 0x0018+ (0x9082 << 16); #define kPETImageIndex 0x0054+(0x1330<< 16 ) #define kPEDirectionDisplayedUIH 0x0065+(0x1005<< 16 )//SH #define kDiffusion_bValueUIH 0x0065+(0x1009<< 16 ) //FD +#define kParallelInformationUIH 0x0065+(0x100D<< 16 ) //SH #define kNumberOfImagesInGridUIH 0x0065+(0x1050<< 16 ) //DS #define kMRVFrameSequenceUIH 0x0065+(0x1050<< 16 ) //SQ #define kDiffusionGradientDirectionUIH 0x0065+(0x1037<< 16 ) //FD @@ -4889,6 +4910,14 @@ double TE = 0.0; //most recent echo time recorded d.CSA.numDti = 1; //printf("%d>>>%g\n", lPos, v[0]); break; } + case kParallelInformationUIH: {//SENSE factor (0065,100d) SH [F:2S] + if (d.manufacturer != kMANUFACTURER_UIH) break; + char accelStr[kDICOMStr]; + dcmStr (lLength, &buffer[lPos], accelStr); + char *ptr; + dcmStrDigitsDotOnlyKey(':', accelStr); //e.g. if "p2s4" return "2", if "s4" return "" + d.accelFactPE = atof(accelStr); + break; } case kNumberOfImagesInGridUIH : if (d.manufacturer != kMANUFACTURER_UIH) break; d.numberOfImagesInGridUIH = dcmStrFloat(lLength, &buffer[lPos]); diff --git a/console/nii_dicom_batch.cpp b/console/nii_dicom_batch.cpp index b9b5dcdc..acc396f9 100644 --- a/console/nii_dicom_batch.cpp +++ b/console/nii_dicom_batch.cpp @@ -980,15 +980,16 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts, 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.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) - pf = (float)pf / (float)d.accelFactPE; //estimate: not sure if we round up or down - pf = (float)d.echoTrainLength / (float)pf; - if (pf < 1.0) //e.g. if difference between lines and echo length not all explained by iPAT (SENSE/GRAPPA) - fprintf(fp, "\t\"PartialFourier\": %g,\n", pf); + if ((!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) + pf = (float)pf / (float)d.accelFactPE; //estimate: not sure if we round up or down + pf = (float)d.echoTrainLength / (float)pf; + if (pf < 1.0) //e.g. if difference between lines and echo length not all explained by iPAT (SENSE/GRAPPA) + fprintf(fp, "\t\"PartialFourier\": %g,\n", pf); } //compute partial Fourier: not reported in XA10, so infer + //printf("PhaseLines=%d EchoTrainLength=%d SENSE=%g\n", d.phaseEncodingLines, d.echoTrainLength, d.accelFactPE); //n.b. we can not distinguish pF from SENSE/GRAPPA for UIH } #endif if (d.CSA.multiBandFactor > 1) //AccelFactorSlice @@ -1018,7 +1019,7 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts, if (bandwidthPerPixelPhaseEncode == 0.0) bandwidthPerPixelPhaseEncode = d.CSA.bandwidthPerPixelPhaseEncode; json_Float(fp, "\t\"BandwidthPerPixelPhaseEncode\": %g,\n", bandwidthPerPixelPhaseEncode ); - if (d.accelFactPE > 1.0) fprintf(fp, "\t\"ParallelReductionFactorInPlane\": %g,\n", d.accelFactPE); + if ((!d.is3DAcq) && (d.accelFactPE > 1.0)) fprintf(fp, "\t\"ParallelReductionFactorInPlane\": %g,\n", d.accelFactPE); //EffectiveEchoSpacing // Siemens bandwidthPerPixelPhaseEncode already accounts for the effects of parallel imaging, // interpolation, phaseOversampling, and phaseResolution, in the context of the size of the