Skip to content

Commit

Permalink
@baxpr kludge (#529)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Jul 31, 2021
1 parent 2554af6 commit 6cdd3f5
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 63 deletions.
32 changes: 22 additions & 10 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4239,9 +4239,8 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
#define kSeriesInstanceUID 0x0020 + (0x000E << 16)
#define kImagePositionPatient 0x0020 + (0x0032 << 16) // Actually !
#define kOrientationACR 0x0020 + (0x0035 << 16)
//#define kTemporalPositionIdentifier 0x0020+(0x0100 << 16 ) //IS
#define kOrientation 0x0020 + (0x0037 << 16)
//#define kTemporalPosition 0x0020+(0x0100 << 16 ) //IS
#define kTemporalPosition 0x0020+(0x0100 << 16 ) //IS
//#define kNumberOfTemporalPositions 0x0020+(0x0105 << 16 ) //IS public tag for NumberOfDynamicScans
#define kTemporalResolution 0x0020 + (0x0110 << 16) //DS
#define kImagesInAcquisition 0x0020 + (0x1002 << 16) //IS
Expand Down Expand Up @@ -4360,7 +4359,7 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
#define kDiffusionDirectionFH 0x2005 + (0x10B2 << 16)
#define kPrivatePerFrameSq 0x2005 + (0x140F << 16)
#define kMRImageDiffBValueNumber 0x2005 + (0x1412 << 16) //IS
//#define kMRImageGradientOrientationNumber 0x2005+(0x1413 << 16) //IS
#define kMRImageGradientOrientationNumber 0x2005+(0x1413 << 16) //IS
#define kSharedFunctionalGroupsSequence 0x5200 + uint32_t(0x9229 << 16) // SQ
#define kPerFrameFunctionalGroupsSequence 0x5200 + uint32_t(0x9230 << 16) // SQ
#define kWaveformSq 0x5400 + (0x0100 << 16)
Expand Down Expand Up @@ -4416,7 +4415,8 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
int imagesInAcquisition = 0;
//int sumSliceNumberMrPhilips = 0;
int sliceNumberMrPhilips = 0;
int volumeNumberMrPhilips = 0;
int volumeNumberMrPhilips = -1;
int gradientOrientationNumberPhilips = -1;
int numberOfFrames = 0;
//int MRImageGradientOrientationNumber = 0;
//int minGradNum = kMaxDTI4D + 1;
Expand Down Expand Up @@ -6114,7 +6114,7 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
}
case kMRfMRIStatusIndicationPhilips: //fmri volume number
if (d.manufacturer != kMANUFACTURER_PHILIPS)
break; //see GE dataset in dcm_qa_nih
break;
volumeNumberMrPhilips = dcmInt(lLength, &buffer[lPos], d.isLittleEndian);
break;
case kMRAcquisitionTypePhilips: //kMRAcquisitionType
Expand Down Expand Up @@ -6390,9 +6390,10 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
// printWarning("expected VR of 2005,140F to be 'SQ' (prior DICOM->DICOM conversion error?)\n");
is2005140FSQ = true;
//is2005140FSQwarned = true;
//case kMRImageGradientOrientationNumber :
// if (d.manufacturer == kMANUFACTURER_PHILIPS)
// MRImageGradientOrientationNumber = dcmStrInt(lLength, &buffer[lPos]);
break;
case kMRImageGradientOrientationNumber :
if (d.manufacturer == kMANUFACTURER_PHILIPS)
gradientOrientationNumberPhilips = dcmStrInt(lLength, &buffer[lPos]);
break;
case kMRImageDiffBValueNumber:
if (d.manufacturer != kMANUFACTURER_PHILIPS)
Expand Down Expand Up @@ -6651,6 +6652,11 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
isOrient = true;
break;
}
case kTemporalPosition: //fall through, both kSliceNumberMrPhilips (2001,100A) and kTemporalPosition are is
if (d.manufacturer != kMANUFACTURER_PHILIPS)
break;
volumeNumberMrPhilips = dcmStrInt(lLength, &buffer[lPos]);
break;
case kTemporalResolution:
temporalResolutionMS = dcmStrFloat(lLength, &buffer[lPos]);
break;
Expand Down Expand Up @@ -7030,12 +7036,12 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
exit(kEXIT_CORRUPT_FILE_FOUND);
#endif
}
if ((numDimensionIndexValues == 0) && (sliceNumberMrPhilips > 0) && (volumeNumberMrPhilips > 0) && (locationsInAcquisitionPhilips > 0)) {//issue529
/*if ((numDimensionIndexValues == 0) && (sliceNumberMrPhilips > 0) && (volumeNumberMrPhilips > 0) && (locationsInAcquisitionPhilips > 0)) {//issue529
int instanceNum = ((volumeNumberMrPhilips-1) * locationsInAcquisitionPhilips) + sliceNumberMrPhilips;
if ((d.imageNum != instanceNum) && (isVerbose))
printWarning("Philips instance number (%d) does not make sense: slice %d of %d, volume %d\n", d.imageNum, sliceNumberMrPhilips, locationsInAcquisitionPhilips, volumeNumberMrPhilips);
d.imageNum = instanceNum;
}
}*/
if ((numberOfFrames > 1) && (numDimensionIndexValues == 0) && (numberOfFrames == nSliceMM)) { //issue 372
fidx *objects = (fidx *)malloc(sizeof(struct fidx) * numberOfFrames);
for (int i = 0; i < numberOfFrames; i++) {
Expand Down Expand Up @@ -7345,6 +7351,12 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
//in practice 0020,0110 not used
//https://github.com/bids-standard/bep001/blob/repetitiontime/Proposal_RepetitionTime.md
}
//start: issue529
if ((!isSameFloat(d.CSA.dtiV[0], 0.0f)) && ((isSameFloat(d.CSA.dtiV[1], 0.0f)) && (isSameFloat(d.CSA.dtiV[2], 0.0f)) && (isSameFloat(d.CSA.dtiV[3], 0.0f)) ) )
gradientOrientationNumberPhilips = kMaxDTI4D + 1; //Philips includes derived Trace/ADC images into raw DTI, these should be removed...
d.rawDataRunNumber = (d.rawDataRunNumber > volumeNumberMrPhilips) ? d.rawDataRunNumber : volumeNumberMrPhilips;
d.rawDataRunNumber = (d.rawDataRunNumber > gradientOrientationNumberPhilips) ? d.rawDataRunNumber : gradientOrientationNumberPhilips;
//end: issue529
if (hasDwiDirectionality)
d.isVectorFromBMatrix = false; //issue 265: Philips/Siemens have both directionality and bmatrix, Bruker only has bmatrix
//printf("%s\t%s\t%s\t%s\t%s_%s\n",d.patientBirthDate, d.procedureStepDescription,d.patientName, fname, d.studyDate, d.studyTime);
Expand Down
124 changes: 71 additions & 53 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,39 @@ const char kFileSep[2] = "/";

#define newTilt

#ifdef USING_R

#ifndef max
#define max(a, b) std::max(a, b)
#endif

#ifndef min
#define min(a, b) std::min(a, b)
#endif

#else

#ifndef max
#define max(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif

#ifndef min
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif

#endif

bool isADCnotDTI(TDTI bvec) { //returns true if bval!=0 but all bvecs == 0 (Philips code for derived ADC image)
return ((!isSameFloat(bvec.V[0], 0.0f)) && //not a B-0 image
((isSameFloat(bvec.V[1], 0.0f)) && (isSameFloat(bvec.V[2], 0.0f)) && (isSameFloat(bvec.V[3], 0.0f))));
}

struct TDCMsort {
uint64_t indx, img;
uint32_t dimensionIndexValues[MAX_NUMBER_OF_DIMENSIONS];
Expand Down Expand Up @@ -1869,11 +1902,6 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,

#endif

bool isADCnotDTI(TDTI bvec) { //returns true if bval!=0 but all bvecs == 0 (Philips code for derived ADC image)
return ((!isSameFloat(bvec.V[0], 0.0f)) && //not a B-0 image
((isSameFloat(bvec.V[1], 0.0f)) && (isSameFloat(bvec.V[2], 0.0f)) && (isSameFloat(bvec.V[3], 0.0f))));
}

unsigned char *removeADC(struct nifti_1_header *hdr, unsigned char *inImg, int numADC) {
//for speed we just clip the number of volumes, the realloc routine would be nice
// we do not want to copy input to a new smaller array since 4D DTI datasets can be huge
Expand Down Expand Up @@ -2461,16 +2489,20 @@ float intersliceDistanceSigned(struct TDICOMdata d1, struct TDICOMdata d2) {

//https://stackoverflow.com/questions/36714030/c-sort-float-array-while-keeping-track-of-indices/36714204
struct TFloatSort {
float value;
int index;
float position;
int volume, index;
};

int compareTFloatSort(const void *a, const void *b) {
struct TFloatSort *a1 = (struct TFloatSort *)a;
struct TFloatSort *a2 = (struct TFloatSort *)b;
if ((*a1).value > (*a2).value)
if ((*a1).volume > (*a2).volume)
return 1;
if ((*a1).value < (*a2).value)
if ((*a1).volume < (*a2).volume)
return -1;
if ((*a1).position > (*a2).position)
return 1;
if ((*a1).position < (*a2).position)
return -1;
//if value is tied, retain index order (useful for TXYZ images?)
if ((*a1).index > (*a2).index)
Expand All @@ -2489,35 +2521,46 @@ bool ensureSequentialSlicePositions(int d3, int d4, struct TDCMsort dcmSort[], s
float dx = intersliceDistanceSigned(dcmList[dcmSort[0].indx], dcmList[dcmSort[1].indx]);
bool isAscending1 = (dx > 0);
bool isConsistent = true;
for (int i = 1; i < d3; i++) {
dx = intersliceDistanceSigned(dcmList[dcmSort[i - 1].indx], dcmList[dcmSort[i].indx]);
bool isAscending = (dx > 0);
if (isAscending != isAscending1)
isConsistent = false; //direction reverses
for (int v = 0; v < d4; v++) {
int volStart = v * d3;
for (int i = 1; i < d3; i++) {
dx = intersliceDistanceSigned(dcmList[dcmSort[volStart + i - 1].indx], dcmList[dcmSort[volStart + i].indx]);
bool isAscending = (dx > 0);
//printf("volume %d slice %d distanceFromSlice1 %g DICOMvolume %d\n", v, i+1, dx, dcmList[dcmSort[volStart + i].indx].rawDataRunNumber);
if (isAscending != isAscending1)
isConsistent = false; //direction reverses
}
}
if (isConsistent)
return true;
printWarning("Order specified by DICOM instance number is not spatial (reordering).\n");
TFloatSort *floatSort = (TFloatSort *)malloc(d3 * sizeof(TFloatSort));
for (int i = 0; i < d3; i++) {
TFloatSort *floatSort = (TFloatSort *)malloc(nConvert * sizeof(TFloatSort));
int minVol = dcmList[dcmSort[0].indx].rawDataRunNumber;
int maxVol = minVol;
for (int i = 0; i < nConvert; i++) {
dx = intersliceDistanceSigned(dcmList[dcmSort[0].indx], dcmList[dcmSort[i].indx]);
floatSort[i].value = dx;
int vol = dcmList[dcmSort[i].indx].rawDataRunNumber;
floatSort[i].volume = vol;
if (vol > kMaxDTI4D) //issue529 Philips derived Trace/ADC embedded into DWI
vol = d4 + 1;
minVol = min(minVol, vol);
maxVol = max(maxVol, vol);
floatSort[i].position = dx;
floatSort[i].index = i;
}
if ((maxVol-minVol+1) != d4)
printError("Check sorted order: 4D dataset has %d volumes, but volume index ranges from %d..%d\n", d4, minVol, maxVol);
else
printWarning("Order specified by DICOM instance number is not spatial (reordering).\n");
TDCMsort *dcmSortIn = (TDCMsort *)malloc(nConvert * sizeof(TDCMsort));
for (int i = 0; i < nConvert; i++)
dcmSortIn[i] = dcmSort[i];
qsort(floatSort, d3, sizeof(struct TFloatSort), compareTFloatSort); //sort based on series and image numbers....
for (int vol = 0; vol < d4; vol++) {
int volInc = vol * d3;
for (int i = 0; i < d3; i++)
dcmSort[volInc + i] = dcmSortIn[volInc + floatSort[i].index];
}
qsort(floatSort, nConvert, sizeof(struct TFloatSort), compareTFloatSort); //sort based on series and image numbers....
for (int i = 0; i < nConvert; i++)
dcmSort[i] = dcmSortIn[floatSort[i].index];
free(floatSort);
free(dcmSortIn);
return false;
} // ensureSequentialSlicePositions()
//#endif //myInstanceNumberOrderIsNotSpatial

void swapDim3Dim4(int d3, int d4, struct TDCMsort dcmSort[]) {
//swap space and time: input A0,A1...An,B0,B1...Bn output A0,B0,A1,B1,...
Expand Down Expand Up @@ -3686,34 +3729,6 @@ int nii_saveNRRD(char *niiFilename, struct nifti_1_header hdr, unsigned char *im

#endif

#ifdef USING_R

#ifndef max
#define max(a, b) std::max(a, b)
#endif

#ifndef min
#define min(a, b) std::min(a, b)
#endif

#else

#ifndef max
#define max(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif

#ifndef min
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif

#endif

void removeSclSlopeInter(struct nifti_1_header *hdr, unsigned char *img) {
//NRRD does not have scl_slope scl_inter. Adjust data if possible
// https://discourse.slicer.org/t/preserve-image-rescale-and-slope-when-saving-in-nrrd-file/13357
Expand Down Expand Up @@ -5490,6 +5505,9 @@ int saveDcm2NiiCore(int nConvert, struct TDCMsort dcmSort[], struct TDICOMdata d
//next: detect variable inter-volume time https://github.com/rordenlab/dcm2niix/issues/184
//if ((nConvert > 1) && ((dcmList[indx0].modality == kMODALITY_PT)|| (opts.isForceOnsetTimes))) {
if ((nConvert > 1) && ((dcmList[indx0].modality == kMODALITY_PT) || ((opts.isForceOnsetTimes) && (dcmList[indx0].manufacturer != kMANUFACTURER_GE)))) {
if (dcmList[dcmSort[0].indx].manufacturer == kMANUFACTURER_PHILIPS)
ensureSequentialSlicePositions(hdr0.dim[3], hdr0.dim[4], dcmSort, dcmList); //issue529
//printf("Bogo529\n"); return EXIT_SUCCESS;
//note: GE 0008,0032 unreliable, see mb=6 data from sw27.0 20201026
//issue 407
int nTR = 0;
Expand Down

0 comments on commit 6cdd3f5

Please sign in to comment.