Skip to content

Commit

Permalink
Discriminate trace from raw GE DWI scans (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Nov 14, 2018
1 parent 62f3b6e commit 80e1404
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
18 changes: 16 additions & 2 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ struct TDICOMdata clear_dicom_data() {
d.isExplicitVR = true;
d.isLittleEndian = true; //DICOM initially always little endian
d.converted2NII = 0;
d.numberOfDiffusionDirectionGE = -1;
d.phaseEncodingGE = kGE_PHASE_ENCODING_POLARITY_UNKNOWN;
d.rtia_timerGE = -1.0;
d.numberOfImagesInGridUIH = 0;
Expand Down Expand Up @@ -3917,6 +3918,7 @@ const uint32_t kEffectiveTE = 0x0018+ (0x9082 << 16);
#define kMRAcquisitionPhaseEncodingStepsInPlane 0x0018+uint32_t(0x9231<< 16 ) //US
#define kNumberOfImagesInMosaic 0x0019+(0x100A<< 16 ) //US NumberOfImagesInMosaic
#define kDwellTime 0x0019+(0x1018<< 16 ) //IS in NSec, see https://github.com/rordenlab/dcm2niix/issues/127
#define kNumberOfDiffusionDirectionGE 0x0019+(0x10E0<< 16) ///DS NumberOfDiffusionDirection:UserData24
#define kLastScanLoc 0x0019+(0x101B<< 16 )
#define kDiffusionDirectionGEX 0x0019+(0x10BB<< 16 ) //DS phase diffusion direction
#define kDiffusionDirectionGEY 0x0019+(0x10BC<< 16 ) //DS frequency diffusion direction
Expand Down Expand Up @@ -3963,14 +3965,15 @@ const uint32_t kEffectiveTE = 0x0018+ (0x9082 << 16);
#define kXYSpacing 0x0028+(0x0030 << 16 ) //DS 'PixelSpacing'
#define kBitsAllocated 0x0028+(0x0100 << 16 )
#define kBitsStored 0x0028+(0x0101 << 16 )//US 'BitsStored'
#define kIsSigned 0x0028+(0x0103 << 16 )
#define kIsSigned 0x0028+(0x0103 << 16 ) //PixelRepresentation
#define kIntercept 0x0028+(0x1052 << 16 )
#define kSlope 0x0028+(0x1053 << 16 )
//#define kSpectroscopyDataPointColumns 0x0028+(0x9002 << 16 ) //IS
#define kGeiisFlag 0x0029+(0x0010 << 16 ) //warn user if dreaded GEIIS was used to process image
#define kCSAImageHeaderInfo 0x0029+(0x1010 << 16 )
#define kCSASeriesHeaderInfo 0x0029+(0x1020 << 16 )
//#define kObjectGraphics 0x0029+(0x1210 << 16 ) //0029,1210 syngoPlatformOOGInfo Object Oriented Graphics
#define kStudyComments 0x0032+(0x4000<< 16 )//LT StudyComments
//#define kObjectGraphics 0x0029+(0x1210 << 16 ) //0029,1210 syngoPlatformOOGInfo Object Oriented Graphics
#define kProcedureStepDescription 0x0040+(0x0254 << 16 )
#define kRealWorldIntercept 0x0040+uint32_t(0x9224 << 16 ) //IS dicm2nii's SlopInt_6_9
#define kRealWorldSlope 0x0040+uint32_t(0x9225 << 16 ) //IS dicm2nii's SlopInt_6_9
Expand Down Expand Up @@ -4705,6 +4708,11 @@ double TE = 0.0; //most recent echo time recorded
case kDwellTime :
d.dwellTime = dcmStrInt(lLength, &buffer[lPos]);
break;
case kNumberOfDiffusionDirectionGE : {
if (d.manufacturer != kMANUFACTURER_GE) break;
float f = dcmStrFloat(lLength, &buffer[lPos]);
d.numberOfDiffusionDirectionGE = round(f);
break; }
case kLastScanLoc :
d.lastScanLoc = dcmStrFloat(lLength, &buffer[lPos]);
break;
Expand Down Expand Up @@ -5510,6 +5518,12 @@ double TE = 0.0; //most recent echo time recorded
//geiisBug = true; //compressed thumbnails do not follow transfer syntax! GE should not re-use pulbic tags for these proprietary images http://sonca.kasshin.net/gdcm/Doc/GE_ImageThumbnails
}
break;
case kStudyComments: {
//char commentStr[kDICOMStr];
//dcmStr (lLength, &buffer[lPos], commentStr);
//printf(">> %s\n", commentStr);
break;
}
case kProcedureStepDescription:
dcmStr (lLength, &buffer[lPos], d.procedureStepDescription);
break;
Expand Down
4 changes: 2 additions & 2 deletions console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ extern "C" {
#define kCCsuf " CompilerNA" //unknown compiler!
#endif

#define kDCMvers "v1.0.20181108 " kJP2suf kLSsuf kCCsuf
#define kDCMvers "v1.0.20181114 " kJP2suf kLSsuf kCCsuf

static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens Mosaic
static const int kMaxDTI4D = 18000; //maximum number of DTI directions for 4D (Philips) images, also maximum number of 3D slices for Philips 3D and 4D images
Expand Down Expand Up @@ -155,7 +155,7 @@ static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
struct TDICOMdata {
long seriesNum;
int xyzDim[5];
int numberOfImagesInGridUIH, phaseEncodingGE, protocolBlockStartGE, protocolBlockLengthGE, modality, dwellTime, effectiveEchoSpacingGE, phaseEncodingLines, phaseEncodingSteps, echoTrainLength, coilCrc, echoNum, sliceOrient, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,locationsInAcquisition, compressionScheme;
int numberOfImagesInGridUIH, numberOfDiffusionDirectionGE, phaseEncodingGE, protocolBlockStartGE, protocolBlockLengthGE, modality, dwellTime, effectiveEchoSpacingGE, phaseEncodingLines, phaseEncodingSteps, echoTrainLength, coilCrc, echoNum, sliceOrient, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,locationsInAcquisition, compressionScheme;
float imagingFrequency, patientWeight, zSpacing, zThick, pixelBandwidth, SAR, phaseFieldofView, accelFactPE, flipAngle, fieldStrength, TE, TI, TR, intenScale, intenIntercept, intenScalePhilips, gantryTilt, lastScanLoc, angulation[4];
float orient[7], patientPosition[4], patientPositionLast[4], xyzMM[4], stackOffcentre[4];
float rtia_timerGE, radionuclidePositronFraction, radionuclideTotalDose, radionuclideHalfLife, doseCalibrationFactor; //PET ISOTOPE MODULE ATTRIBUTES (C.8-57)
Expand Down
17 changes: 13 additions & 4 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ void geCorrectBvecs(struct TDICOMdata *d, int sliceDir, struct TDTI *vx){
//COL then if swap the x and y value and reverse the sign on the z value.
//If the phase encoding is not COL, then just reverse the sign on the x value.
if (d->manufacturer != kMANUFACTURER_GE) return;

if (d->CSA.numDti < 1) return;
if ((toupper(d->patientOrient[0])== 'H') && (toupper(d->patientOrient[1])== 'F') && (toupper(d->patientOrient[2])== 'S'))
; //participant was head first supine
Expand Down Expand Up @@ -219,6 +218,7 @@ void geCorrectBvecs(struct TDICOMdata *d, int sliceDir, struct TDTI *vx){
printMessage("Saving %d DTI gradients. GE Reorienting %s : please validate. isCol=%d sliceDir=%d flp=%d %d %d\n", d->CSA.numDti, d->protocolName, col, sliceDir, flp.v[0], flp.v[1],flp.v[2]);
if (!col)
printMessage(" reorienting for ROW phase-encoding untested.\n");
bool scaledBValWarning = false;
for (int i = 0; i < d->CSA.numDti; i++) {
float vLen = sqrt( (vx[i].V[1]*vx[i].V[1])
+ (vx[i].V[2]*vx[i].V[2])
Expand All @@ -231,7 +231,10 @@ void geCorrectBvecs(struct TDICOMdata *d, int sliceDir, struct TDTI *vx){
if ((vLen > 0.03) && (vLen < 0.97)) {
//bVal scaled by norm(g)^2 https://github.com/rordenlab/dcm2niix/issues/163
float bVal = vx[i].V[0] * (vLen * vLen);
printMessage("GE BVal scaled %g -> %g\n", vx[i].V[0], bVal);
if (!scaledBValWarning) {
printMessage("GE BVal scaling (e.g. %g -> %g s/mm^2)\n", vx[i].V[0], bVal);
scaledBValWarning = true;
}
vx[i].V[0] = bVal;
vx[i].V[1] = vx[i].V[1]/vLen;
vx[i].V[2] = vx[i].V[2]/vLen;
Expand Down Expand Up @@ -1327,14 +1330,20 @@ int * nii_SaveDTI(char pathoutname[],int nConvert, struct TDCMsort dcmSort[],str
*numADC = 0;
bvals = (float *) malloc(numDti * sizeof(float));
int numGEwarn = 0;
bool isGEADC = (dcmList[indx0].numberOfDiffusionDirectionGE == 0) ;
for (int i = 0; i < numDti; i++) {
bvals[i] = vx[i].V[0];
//printMessage("---bxyz %g %g %g %g\n",vx[i].V[0],vx[i].V[1],vx[i].V[2],vx[i].V[3]);
//Philips includes derived isotropic images
//if (((dcmList[indx0].manufacturer == kMANUFACTURER_GE) || (dcmList[indx0].manufacturer == kMANUFACTURER_PHILIPS)) && (isADCnotDTI(vx[i]))) {
if (((dcmList[indx0].manufacturer == kMANUFACTURER_GE)) && (isADCnotDTI(vx[i]))) {
numGEwarn += 1;
vx[i].V[0] = 0;
if (isGEADC) { //e.g. GE Trace where bval=900, bvec=0,0,0
*numADC = *numADC + 1;
//printWarning("GE ADC volume %d\n", i+1);
bvals[i] = kADCval;
} else
vx[i].V[0] = 0; //e.g. GE raw B=0 where bval=900, bvec=0,0,0
} //see issue 245
if (((dcmList[indx0].manufacturer == kMANUFACTURER_PHILIPS)) && (isADCnotDTI(vx[i]))) {
*numADC = *numADC + 1;
Expand Down Expand Up @@ -2950,7 +2959,7 @@ int saveDcm2NiiCore(int nConvert, struct TDCMsort dcmSort[],struct TDICOMdata dc
printMessage("Ignoring derived image(s) of series %ld %s\n", dcmList[indx].seriesNum, nameList->str[indx]);
return EXIT_SUCCESS;
}
if ((opts.isIgnoreDerivedAnd2D) && ((dcmList[indx].isLocalizer) || (strcmp(dcmList[indx].sequenceName, "_fl3d1_ns")== 0) || (strcmp(dcmList[indx].sequenceName, "_fl2d1")== 0)) ) {
if ((opts.isIgnoreDerivedAnd2D) && ((dcmList[indx].isLocalizer) || (strcmp(dcmList[indx].sequenceName, "_tfl2d1")== 0) || (strcmp(dcmList[indx].sequenceName, "_fl3d1_ns")== 0) || (strcmp(dcmList[indx].sequenceName, "_fl2d1")== 0)) ) {
printMessage("Ignoring localizer (sequence %s) of series %ld %s\n", dcmList[indx].sequenceName, dcmList[indx].seriesNum, nameList->str[indx]);
return EXIT_SUCCESS;
}
Expand Down

0 comments on commit 80e1404

Please sign in to comment.