Skip to content

Commit

Permalink
Renambed ASL fields to match new BIDS specification (https://bids-spe…
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Mar 14, 2024
1 parent f8baa94 commit 484de5b
Showing 1 changed file with 14 additions and 123 deletions.
137 changes: 14 additions & 123 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1371,7 +1371,6 @@ tse3d: T2*/
}
if (d.patientSex != '?')
fprintf(fp, "\t\"PatientSex\": \"%c\",\n", d.patientSex);
json_Float(fp, "\t\"PatientSize\": %g,\n", d.patientSize);
json_Float(fp, "\t\"PatientWeight\": %g,\n", d.patientWeight);
//d.patientBirthDate //convert from DICOM YYYYMMDD to JSON
//d.patientAge //4-digit Age String: nnnD, nnnW, nnnM, nnnY;
Expand All @@ -1386,7 +1385,7 @@ tse3d: T2*/
}
if (d.isQuadruped)
json_Bool(fp, "\t\"Quadruped\": %s,\n", true); // BIDS suggests 0018,9020 but Siemens V-series do not populate this, alternatives are CSA or (0018,0021) CS [SK\MTC\SP]
json_Str(fp, "\t\"BodyPart\": \"%s\",\n", d.bodyPartExamined); //renamed to match BIDS https://bids-specification.readthedocs.io/en/stable/modality-specific-files/positron-emission-tomography.html
json_Str(fp, "\t\"BodyPartExamined\": \"%s\",\n", d.bodyPartExamined);
json_Str(fp, "\t\"PatientPosition\": \"%s\",\n", d.patientOrient); // 0018,5100 = PatientPosition in DICOM
json_Str(fp, "\t\"ProcedureStepDescription\": \"%s\",\n", d.procedureStepDescription);
json_Str(fp, "\t\"SoftwareVersions\": \"%s\",\n", d.softwareVersions);
Expand Down Expand Up @@ -1498,110 +1497,19 @@ tse3d: T2*/
if ((d.isRealIsPhaseMapHz) && ((d.manufacturer == kMANUFACTURER_GE) || (d.isHasReal)))
fprintf(fp, "\t\"Units\": \"Hz\",\n"); //
//PET ISOTOPE MODULE ATTRIBUTES
json_Str(fp, "\t\"TracerRadionuclide\": \"%s\",\n", d.tracerRadionuclide);
json_Str(fp, "\t\"Radiopharmaceutical\": \"%s\",\n", d.radiopharmaceutical);
json_Float(fp, "\t\"RadionuclidePositronFraction\": %g,\n", d.radionuclidePositronFraction);
json_Float(fp, "\t\"InjectedRadioactivity\": %g,\n", d.radionuclideTotalDose); //renamed https://bids-specification.readthedocs.io/en/stable/glossary.html#objects.metadata.InjectedRadioactivity
json_Float(fp, "\t\"RadionuclideTotalDose\": %g,\n", d.radionuclideTotalDose);
json_Float(fp, "\t\"RadionuclideHalfLife\": %g,\n", d.radionuclideHalfLife);
json_Float(fp, "\t\"DoseCalibrationFactor\": %g,\n", d.doseCalibrationFactor);
json_Float(fp, "\t\"IsotopeHalfLife\": %g,\n", d.ecat_isotope_halflife);
json_Float(fp, "\t\"Dosage\": %g,\n", d.ecat_dosage);
json_Str(fp, "\t\"ConvolutionKernel\": \"%s\",\n", d.convolutionKernel);
json_Str(fp, "\t\"Units\": \"%s\",\n", d.unitsPT); //https://github.com/bids-standard/bids-specification/pull/773
json_Str(fp, "\t\"DecayCorrectionFactor\": \"%s\",\n", d.decayCorrection); //renamed https://bids-specification.readthedocs.io/en/stable/glossary.html#objects.metadata.DecayCorrectionFactor
json_Str(fp, "\t\"DecayCorrection\": \"%s\",\n", d.decayCorrection);
json_Str(fp, "\t\"AttenuationCorrectionMethod\": \"%s\",\n", d.attenuationCorrectionMethod);
json_Str(fp, "\t\"ReconstructionMethod\": \"%s\",\n", d.reconstructionMethod);
//START issue 802
char reconMethodName[kDICOMStrLarge] = "";
//start of autogenerated text
if (strstr(d.reconstructionMethod, "PSF+TOF3i21s"))
strcpy(reconMethodName, "Point-Spread Function + Time Of Flight");
else if (strstr(d.reconstructionMethod, "PSF TOF 3D OSEM"))
strcpy(reconMethodName, "Point-Spread Function 3D Time Of Flight");
else if (strstr(d.reconstructionMethod, "OP-OSEM"))
strcpy(reconMethodName, "Ordinary Poisson - Ordered Subset Expectation Maximization");
else if (strstr(d.reconstructionMethod, "OSEM3D-OP-PSF"))
strcpy(reconMethodName, "Ordinary Poisson 3D Ordered Subset Expectation Maximization + Point-Spread Function");
else if (strstr(d.reconstructionMethod, "LOR-RAMLA"))
strcpy(reconMethodName, "Line Of Response - Row Action Maximum Likelihood");
else if (strstr(d.reconstructionMethod, "3D-RAMLA"))
strcpy(reconMethodName, "3D Row Action Maximum Likelihood");
else if (strstr(d.reconstructionMethod, "3DRP"))
strcpy(reconMethodName, "3DRP");
else if (strstr(d.reconstructionMethod, "3D Kinahan-Rogers"))
strcpy(reconMethodName, "3D Kinahan-Rogers");
//end of autogenerated text
if (strlen(reconMethodName) < 1) {
if (strstr(d.reconstructionMethod, "OSEM"))
strcat(reconMethodName, "Ordered Subset Expectation Maximization ");
else if (strstr(d.reconstructionMethod, "OS"))
strcat(reconMethodName, "Ordered Subset ");
if (strstr(d.reconstructionMethod, "LOR"))
strcat(reconMethodName, "Line Of Response ");
if (strstr(d.reconstructionMethod, "RAMLA"))
strcat(reconMethodName, "Row Action Maximum Likelihood ");
if (strstr(d.reconstructionMethod, "OP"))
strcat(reconMethodName, "Ordinary Poisson ");
if (strstr(d.reconstructionMethod, "PSF"))
strcat(reconMethodName, "Point-Spread Function modelling ");
if (strstr(d.reconstructionMethod, "TOF"))
strcat(reconMethodName, "Time Of Flight ");
if (strstr(d.reconstructionMethod, "TF"))
strcat(reconMethodName, "Time Of Flight ");
if (strstr(d.reconstructionMethod, "VPHD"))
strcat(reconMethodName, "VUE Point HD ");
else if (strstr(d.reconstructionMethod, "VPHD-S"))
strcat(reconMethodName, "3D Ordered Subset Expectation Maximization with Point-Spread Function modelling ");
if (strstr(d.reconstructionMethod, "VPFX"))
strcat(reconMethodName, "VUE Point HD using Time Of Flight ");
else if (strstr(d.reconstructionMethod, "VPFXS"))
strcat(reconMethodName, "VUE Point HD using Time Of Flight with Point-Spread Function modelling ");
if (strstr(d.reconstructionMethod, "Q.Clear"))
strcat(reconMethodName, "VUE Point HD with regularization (smoothing) ");
if (strstr(d.reconstructionMethod, "BLOB"))
strcat(reconMethodName, "3D spherically symmetric basis function ");
if (strstr(d.reconstructionMethod, "FilteredBackProjection"))
strcat(reconMethodName, "Filtered Back Projection ");
if (strstr(d.reconstructionMethod, "3DRP"))
strcat(reconMethodName, "3D Kinahan-Rogers ");
//remove trailing spaces
if ((strlen(reconMethodName) > 0) && (reconMethodName[strlen(reconMethodName) -1] == ' '))
reconMethodName[strlen(reconMethodName) -1] = '\0';
}
json_Str(fp, "\t\"ReconMethodName\": \"%s\",\n", reconMethodName);
int iterations = 0;
//note, some vendors write 'OSEM3D-OP-PSFi10s16' others 'OP-OSEM4i21s'
// order matters `OP-OSEM4i21s` should have i=4 NOT i=21
bool sEnd = d.reconstructionMethod[strlen(d.reconstructionMethod) -1] == 's';
for (int i = 1; i < 33; i++) {
char stri[12];
if (sEnd)
snprintf(stri, 12, "%di", i);
else
snprintf(stri, 12, "i%d", i);
if (strstr(d.reconstructionMethod, stri))
iterations = i;
}
int subsets = 0;
for (int i = 1; i < 32; i++) {
char stri[12];
if (sEnd)
snprintf(stri, 12, "%ds", i);
else
snprintf(stri, 12, "s%d", i);
if (strstr(d.reconstructionMethod, stri))
subsets = i;
}
if ((subsets > 0) && (iterations > 0)) {
fprintf(fp, "\t\"ReconMethodParameterLabels\": [\"subsets\", \"iterations\"],\n");
fprintf(fp, "\t\"ReconMethodParameterValues\": [\n");
fprintf(fp, "\t\t%d,\n", subsets);
fprintf(fp, "\t\t%d\t],\n", iterations);
}
//printf("::::%s ->'%s' : s%d i%d\n", d.reconstructionMethod, reconMethodName, subsets, iterations);
//END issue 802

json_Float(fp, "\t\"ScatterFraction\": %g,\n", d.scatterFraction);
//json_Float(fp, "\t\"DecayFactor\": %g,\n", d.decayFactor);
if (dti4D->decayFactor[0] >= 0.0) { //see BEP009 PET https://docs.google.com/document/d/1mqMLnxVdLwZjDd4ZiWFqjEAmOmfcModA_R535v3eQs0
fprintf(fp, "\t\"DecayFactor\": [\n");
for (int i = 0; i < h->dim[4]; i++) {
Expand Down Expand Up @@ -1844,11 +1752,11 @@ tse3d: T2*/
repetitionTimePreparation = d.TR;
json_FloatNotNan(fp, "\t\"InversionTime\": %g,\n", csaAscii.alTI[2] * (1.0 / 1000000.0)); //ms->sec
json_FloatNotNan(fp, "\t\"BolusDuration\": %g,\n", csaAscii.alTI[0] * (1.0 / 1000000.0)); //usec -> sec
json_Float(fp, "\t\"TagRFFlipAngle\": %g,\n", csaAscii.alFree[4]);
json_Float(fp, "\t\"TagRFDuration\": %g,\n", csaAscii.alFree[5] / 1000000.0); //usec -> sec
json_Float(fp, "\t\"LabelingPulseFlipAngle\": %g,\n", csaAscii.alFree[4]); //BIDS renaming TagRFFlipAngle -> LabelingPulseFlipAngle
json_Float(fp, "\t\"LabelingPulseDuration\": %g,\n", csaAscii.alFree[5] / 1000000.0); //BIDS renaming TagRFDuration -> LabelingPulseDuration usec -> sec
json_Float(fp, "\t\"TagRFSeparation\": %g,\n", csaAscii.alFree[6] / 1000000.0); //usec -> sec
json_FloatNotNan(fp, "\t\"MeanTagGradient\": %g,\n", csaAscii.adFree[0]); //mTm
json_FloatNotNan(fp, "\t\"TagGradientAmplitude\": %g,\n", csaAscii.adFree[1]); //mTm
json_FloatNotNan(fp, "\t\"LabelingPulseAverageGradient\": %g,\n", csaAscii.adFree[0]); //BDS renaming MeanTagGradient -> LabelingPulseAverageGradient mTm
json_FloatNotNan(fp, "\t\"LabelingPulseMaximumGradient\": %g,\n", csaAscii.adFree[1]); //BIDS renaming TagGradientAmplitude -> LabelingPulseMaximumGradient mTm
json_Float(fp, "\t\"TagDuration\": %g,\n", csaAscii.alFree[9] / 1000.0); //ms -> sec
json_Float(fp, "\t\"MaximumT1Opt\": %g,\n", csaAscii.alFree[10] / 1000.0); //ms -> sec
//report post label delay
Expand All @@ -1861,7 +1769,7 @@ tse3d: T2*/
nPLD++;
} //for k
if (nPLD > 0) { // record PostLabelDelays, these are listed as "PLD0","PLD1",etc in PDF
fprintf(fp, "\t\"InitialPostLabelDelay\": [\n"); //https://docs.google.com/document/d/15tnn5F10KpgHypaQJNNGiNKsni9035GtDqJzWqkkP6c/edit#
fprintf(fp, "\t\"PostLabelingDelay\": [\n"); //BIDS renaming InitialPostLabelDelay -> PostLabelingDelay https://docs.google.com/document/d/15tnn5F10KpgHypaQJNNGiNKsni9035GtDqJzWqkkP6c/edit#
for (int i = 0; i < nPLD; i++) {
if (i != 0)
fprintf(fp, ",\n");
Expand Down Expand Up @@ -6951,7 +6859,7 @@ void setBidsPhilips(struct TDICOMdata *d, int nConvert, int isVerbose) {
strcat(suffixBIDS,modalityBIDS);
}
//if ((isVerbose > 0) || (strlen(dataTypeBIDS) < 1))
if (isVerbose > 0)
//if (isVerbose > 0)
printf("::autoBids:Philips pulseSeq:'%s' scanSeq:'%s' seqVariant:'%s'\n",
d->pulseSequenceName, d->scanningSequence, d->sequenceVariant);
if (isDerived)
Expand Down Expand Up @@ -7529,6 +7437,8 @@ int sliceTimingCore(struct TDCMsort *dcmSort, struct TDICOMdata *dcmList, struct
sliceDir = -1; //not sure how to handle negative determinants?
}
if (sliceDir < 0) {
if((dcmList[dcmSort[0].indx].manufacturer == kMANUFACTURER_SIEMENS) && (dcmList[dcmSort[0].indx].CSA.mosaicSlices < 2))
dcmList[dcmSort[0].indx].CSA.protocolSliceNumber1 = -1;
if ((dcmList[dcmSort[0].indx].manufacturer == kMANUFACTURER_UIH) || (dcmList[dcmSort[0].indx].manufacturer == kMANUFACTURER_GE))
dcmList[dcmSort[0].indx].CSA.protocolSliceNumber1 = -1;
}
Expand Down Expand Up @@ -8434,19 +8344,6 @@ int saveDcm2Nii(int nConvert, struct TDCMsort dcmSort[], struct TDICOMdata dcmLi
mrifsStruct.dicomlst = new char*[nConvert];
mrifsStruct.nDcm = nConvert;

// retrieve pulseSequenceDetails (tSequenceFileName)
struct TDICOMdata *d = &(mrifsStruct.tdicomData);
strcpy(mrifsStruct.pulseSequenceDetails, "");
if ((d->manufacturer == kMANUFACTURER_SIEMENS) && (d->CSA.SeriesHeader_offset > 0) && (d->CSA.SeriesHeader_length > 0)) {
float shimSetting[8];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrLarge];
TCsaAscii csaAscii;
siemensCsaAscii(nameList->str[indx0], &csaAscii, d->CSA.SeriesHeader_offset, d->CSA.SeriesHeader_length, shimSetting, coilID, consistencyInfo, coilElements, pulseSequenceDetails, fmriExternalInfo, protocolName, wipMemBlock);
if (strlen(pulseSequenceDetails) >= kDICOMStr)
pulseSequenceDetails[kDICOMStr - 1] = 0;
strcpy(mrifsStruct.pulseSequenceDetails, pulseSequenceDetails);
}

dcmListDump(nConvert, dcmSort, dcmList, nameList, opts);

mrifsStruct_vector.push_back(mrifsStruct);
Expand Down Expand Up @@ -10113,16 +10010,10 @@ void dcmListDump(int nConvert, struct TDCMsort dcmSort[], struct TDICOMdata dcmL
memset(mrifsStruct.dicomlst[i], 0, strlen(nameList->str[indx])+1);
memcpy(mrifsStruct.dicomlst[i], nameList->str[indx], strlen(nameList->str[indx]));

FILE *fp = stdout;
const char *imagelist = getenv("MGH_DCMUNPACK_IMAGELIST");
if (imagelist != NULL)
fp = fopen(imagelist, "a");

fprintf(fp, "%s %ld %s %s %f %f %f %f\\%f %c %f %s %s\n",
printMessage("%s %ld %s %s %f %f %f %f\\%f %c %f %s %s\n",
dcmList[indx].patientName, dcmList[indx].seriesNum, dcmList[indx].studyDate, dcmList[indx].studyTime,
dcmList[indx].TE, dcmList[indx].TR, dcmList[indx].flipAngle, dcmList[indx].xyzMM[1], dcmList[indx].xyzMM[2],
dcmList[indx].phaseEncodingRC, dcmList[indx].pixelBandwidth, nameList->str[indx], dcmList[indx].imageType);
fclose(fp);
}
}
#endif
#endif

0 comments on commit 484de5b

Please sign in to comment.