Skip to content

Commit

Permalink
Merge pull request #813 from CGSchwarzMayo/DeIdentificationMethod_json
Browse files Browse the repository at this point in the history
Add DeidentificationMethod and DeidentificationMethodCodeSequence to json
  • Loading branch information
neurolabusc authored Aug 27, 2024
2 parents b95524c + ed3f8a5 commit fda03a5
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 deletions.
4 changes: 4 additions & 0 deletions console/dcm2niix_fswrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,4 +476,8 @@ void dcm2niix_fswrapper::seriesInfoDump(FILE *fpdump, const MRIFSSTRUCT *pmrifsS

// dcm2niix doesn't seem to retrieve this 0x51, 0x1016
//fprintf(fpdump, "SiemensCrit %s\n",e->d.string);

// kDeidentificationMethod 0x0012 + (0x0063 << 16) // '0012' '0063' 'LO' 'DeidentificationMethod'
fprintf(fpdump, "DeidentificationMethod %s\n", tdicomData->deidentificationMethod);

}
42 changes: 38 additions & 4 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4391,6 +4391,11 @@ struct TDICOMdata readDICOMx(char *fname, struct TDCMprefs *prefs, struct TDTI4D
#define kPatientWeight 0x0010 + (0x1030 << 16)
#define kAnatomicalOrientationType 0x0010 + (0x2210 << 16)
#define kDeidentificationMethod 0x0012 + (0x0063 << 16) //[DICOMANON, issue 383
#define kDeidentificationMethodCodeSequence 0x0012 + (0x0064 << 16)
#define kCodeValue 0x0008 + (0x0100 << 16)
#define kCodingSchemeDesignator 0x0008 + (0x0102 << 16)
#define kCodingSchemeVersion 0x0008 + (0x0103 << 16)
#define kCodeMeaning 0x0008 + (0x0104 << 16)
#define kBodyPartExamined 0x0018 + (0x0015 << 16)
#define kBodyPartExamined 0x0018 + (0x0015 << 16)
#define kScanningSequence 0x0018 + (0x0020 << 16)
Expand Down Expand Up @@ -4791,6 +4796,7 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
bool isPaletteColor = false;
bool isInterpolated = false;
bool isIconImageSequence = false;
bool isDeidentificationMethodCodeSequence = false;
int sqDepthIcon = -1;
bool isSwitchToImplicitVR = false;
bool isSwitchToBigEndian = false;
Expand Down Expand Up @@ -5311,6 +5317,8 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
//return d;
}
if (lLength > 0) //issue695: skip empty tags, "gdcmanon --dumb --empty 0018,0089 good.dcm bad.dcm"
if(sqDepth < 1 && isDeidentificationMethodCodeSequence && groupElement != kItemDelimitationTag && groupElement != kItemTag )
isDeidentificationMethodCodeSequence = false;
switch (groupElement) {
case kMediaStorageSOPClassUID: {
char mediaUID[kDICOMStr];
Expand Down Expand Up @@ -5671,15 +5679,41 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
break;
}
case kDeidentificationMethod: { //issue 383
char anonTxt[kDICOMStr];
dcmStr(lLength, &buffer[lPos], anonTxt);
int slen = (int)strlen(anonTxt);
if ((slen < 10) || (strstr(anonTxt, "DICOMANON") == NULL))
dcmStr(lLength, &buffer[lPos], d.deidentificationMethod);
int slen = (int)strlen(d.deidentificationMethod);
if ((slen < 10) || (strstr(d.deidentificationMethod, "DICOMANON") == NULL))
break;
isDICOMANON = true;
printWarning("Matlab DICOMANON can scramble SeriesInstanceUID (0020,000e) and remove crucial data (see issue 383). \n");
break;
}
case kDeidentificationMethodCodeSequence: {
isDeidentificationMethodCodeSequence = true;
break;
}
case kCodeValue: {
if(isDeidentificationMethodCodeSequence && d.deID_CS_n < MAX_DEID_CS)
dcmStr(lLength, &buffer[lPos], d.deID_CS[d.deID_CS_n].CodeValue);
break;
}
case kCodingSchemeDesignator: {
if(isDeidentificationMethodCodeSequence && d.deID_CS_n < MAX_DEID_CS)
dcmStr(lLength, &buffer[lPos], d.deID_CS[d.deID_CS_n].CodingSchemeDesignator);
break;
}
case kCodingSchemeVersion: {
if(isDeidentificationMethodCodeSequence && d.deID_CS_n < MAX_DEID_CS)
dcmStr(lLength, &buffer[lPos], d.deID_CS[d.deID_CS_n].CodingSchemeVersion);
break;
}
case kCodeMeaning: {
if(isDeidentificationMethodCodeSequence && d.deID_CS_n < MAX_DEID_CS)
{
dcmStr(lLength, &buffer[lPos], d.deID_CS[d.deID_CS_n].CodeMeaning);
d.deID_CS_n++;
}
break;
}
case kPatientID:
if (strlen(d.patientID) > 1)
break;
Expand Down
13 changes: 12 additions & 1 deletion console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ static const int kMaxOverlay = 16; //even group values 0x6000..0x601E
// Maximum number of dimensions for .dimensionIndexValues, i.e. possibly the
// number of axes in the output .nii.
static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
// Maximum supported number of entries in DeidentificationMethodCodeSequence
// Any additional will be ignored
static const uint8_t MAX_DEID_CS = 10;
struct TDTI {
float V[4];
//int totalSlicesIn4DOrder;
Expand Down Expand Up @@ -235,9 +238,16 @@ static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
char bidsEntitySuffix[kDICOMStrLarge]; //anat, func, dwi
char bidsTask[kDICOMStr]; //rest, naming40
};
struct TDeIDCodeSequence {
char CodeValue[kDICOMStr];
char CodeMeaning[kDICOMStrLarge];
char CodingSchemeDesignator[kDICOMStr];
char CodingSchemeVersion[kDICOMStr];
};
struct TDICOMdata {
long seriesNum;
int xyzDim[5];
int deID_CS_n = 0;
uint32_t coilCrc, seriesUidCrc, instanceUidCrc;
int overlayStart[kMaxOverlay];
int postLabelDelay, shimGradientX, shimGradientY, shimGradientZ, phaseNumber, spoiling, mtState, partialFourierDirection, interp3D, aslFlags, durationLabelPulseGE, epiVersionGE, internalepiVersionGE, maxEchoNumGE, rawDataRunNumber, numberOfTR, numberOfImagesInGridUIH, numberOfDiffusionT2GE, numberOfDiffusionDirectionGE, tensorFileGE, diffCyclingModeGE, phaseEncodingGE, protocolBlockStartGE, protocolBlockLengthGE, modality, dwellTime, effectiveEchoSpacingGE, phaseEncodingLines, phaseEncodingSteps, frequencyEncodingSteps, phaseEncodingStepsOutOfPlane, echoTrainLength, echoNum, sliceOrient, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,locationsInAcquisition, locationsInAcquisitionConflict, compressionScheme;
Expand All @@ -248,12 +258,13 @@ static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
float pixelPaddingValue; // used for both FloatPixelPaddingValue (0028, 0122) and PixelPaddingValue (0028, 0120); NaN if not present.
double imagingFrequency, acquisitionDuration, triggerDelayTime, RWVScale, RWVIntercept, dateTime, acquisitionTime, acquisitionDate, bandwidthPerPixelPhaseEncode;
char parallelAcquisitionTechnique[kDICOMStr], radiopharmaceutical[kDICOMStr], convolutionKernel[kDICOMStr], unitsPT[kDICOMStr], tracerRadionuclide[kDICOMStr], decayCorrection[kDICOMStr], attenuationCorrectionMethod[kDICOMStr],reconstructionMethod[kDICOMStr], transferSyntax[kDICOMStr];
char prescanReuseString[kDICOMStr], imageOrientationText[kDICOMStr], pulseSequenceName[kDICOMStr], coilElements[kDICOMStr], coilName[kDICOMStr], phaseEncodingDirectionDisplayedUIH[kDICOMStr], imageBaseName[kDICOMStr], stationName[kDICOMStr], studyDescription[kDICOMStr], softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionName[kDICOMStr], referringPhysicianName[kDICOMStr], instanceUID[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageTypeText[kDICOMStr], imageType[kDICOMStr], institutionalDepartmentName[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr], accessionNumber[kDICOMStr], seriesDescription[kDICOMStr], studyID[kDICOMStr], sequenceName[kDICOMStr], protocolName[kDICOMStr],sequenceVariant[kDICOMStr],scanningSequence[kDICOMStr], patientBirthDate[kDICOMStr], patientAge[kDICOMStr], studyDate[kDICOMStr],studyTime[kDICOMStr];
char prescanReuseString[kDICOMStr], imageOrientationText[kDICOMStr], pulseSequenceName[kDICOMStr], coilElements[kDICOMStr], coilName[kDICOMStr], phaseEncodingDirectionDisplayedUIH[kDICOMStr], imageBaseName[kDICOMStr], stationName[kDICOMStr], studyDescription[kDICOMStr], softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionName[kDICOMStr], referringPhysicianName[kDICOMStr], instanceUID[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageTypeText[kDICOMStr], imageType[kDICOMStr], institutionalDepartmentName[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr], accessionNumber[kDICOMStr], seriesDescription[kDICOMStr], studyID[kDICOMStr], sequenceName[kDICOMStr], protocolName[kDICOMStr],sequenceVariant[kDICOMStr],scanningSequence[kDICOMStr], patientBirthDate[kDICOMStr], patientAge[kDICOMStr], studyDate[kDICOMStr],studyTime[kDICOMStr], deidentificationMethod[kDICOMStr];
char deepLearningText[kDICOMStrLarge], scanOptions[kDICOMStrLarge], institutionAddress[kDICOMStrLarge], imageComments[kDICOMStrLarge];
uint32_t dimensionIndexValues[MAX_NUMBER_OF_DIMENSIONS];
struct TCSAdata CSA;
bool isDeepLearning, isVariableFlipAngle, isQuadruped, isRealIsPhaseMapHz, isPrivateCreatorRemap, isHasOverlay, isEPI, isIR, isPartialFourier, isDiffusion, isVectorFromBMatrix, isRawDataStorage, isGrayscaleSoftcopyPresentationState, isStackableSeries, isCoilVaries, isNonParallelSlices, isBVecWorldCoordinates, isSegamiOasis, isXA10A, isScaleOrTEVaries, isScaleVariesEnh, isDerived, isXRay, isMultiEcho, isValid, is3DAcq, is2DAcq, isExplicitVR, isLittleEndian, isPlanarRGB, isSigned, isHasPhase, isHasImaginary, isHasReal, isHasMagnitude,isHasMixed, isFloat, isResampled, isLocalizer;
char phaseEncodingRC, patientSex;
struct TDeIDCodeSequence deID_CS[MAX_DEID_CS];
};
struct TDCMprefs {
int isVerbose, compressFlag, isIgnoreTriggerTimes;
Expand Down
18 changes: 18 additions & 0 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,24 @@ tse3d: T2*/
fprintf(fp, "\t\"NonlinearGradientCorrection\": false,\n");
if (d.isDerived) //DICOM is derived image or non-spatial file (sounds, etc)
fprintf(fp, "\t\"RawImage\": false,\n");
json_Str(fp, "\t\"DeidentificationMethod\": \"%s\",\n", d.deidentificationMethod);
if(d.deID_CS_n>0)
{
fprintf(fp, "\t\"DeidentificationMethodCodeSequence\": [ \n");
for (int i = 0; i < d.deID_CS_n && i < MAX_DEID_CS; i++)
{
fprintf(fp, "\t { \n");
json_Str(fp, "\t\t\"CodeValue\": \"%s\",\n", d.deID_CS[i].CodeValue);
json_Str(fp, "\t\t\"CodingSchemeDesignator\": \"%s\",\n", d.deID_CS[i].CodingSchemeDesignator);
json_Str(fp, "\t\t\"CodingSchemeVersion\": \"%s\",\n", d.deID_CS[i].CodingSchemeVersion);
json_Str(fp, "\t\t\"CodeMeaning\": \"%s\"\n", d.deID_CS[i].CodeMeaning);
if(i+1 < d.deID_CS_n)
fprintf(fp, "\t },\n");
else
fprintf(fp, "\t }\n");
}
fprintf(fp, "\t],\n");
}
if (d.seriesNum > 0)
fprintf(fp, "\t\"SeriesNumber\": %ld,\n", d.seriesNum);
//Chris Gorgolewski: BIDS standard specifies ISO8601 date-time format (Example: 2016-07-06T12:49:15.679688)
Expand Down

0 comments on commit fda03a5

Please sign in to comment.