Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development #745

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ static const int kMaxDTI4D = kMaxSlice2D; //issue460: maximum number of DTI dire

#define kDICOMStr 66 //64 characters plus NULL https://github.com/rordenlab/dcm2niix/issues/268
#define kDICOMStrLarge 256
#define kDICOMStrExtraLarge 65536 // for Siemens WipMemBlock only


#define kMANUFACTURER_UNKNOWN 0
#define kMANUFACTURER_SIEMENS 1
Expand Down
83 changes: 74 additions & 9 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ float readKeyFloat(const char *key, char *buffer, int remLength) { //look for te
return atof(str);
} //readKeyFloat()

void readKeyStr(const char *key, char *buffer, int remLength, char *outStr) {
void readKeyStr(const char *key, char *buffer, int remLength, char *outStr, int outStrLen) {
//if key is CoilElementID.tCoilID the string 'CoilElementID.tCoilID = ""Head_32""' returns 'Head32'
strcpy(outStr, "");
char *keyPos = (char *)memmem(buffer, remLength, key, strlen(key));
Expand All @@ -629,7 +629,7 @@ void readKeyStr(const char *key, char *buffer, int remLength, char *outStr) {
tmpstr[1] = 0;
bool isQuote = false;
while ((i < remLength) && (keyPos[i] != 0x0A)) {
if ((isQuote) && (keyPos[i] != '"') && (outLen < kDICOMStrLarge)) {
if ((isQuote) && (keyPos[i] != '"') && (outLen < outStrLen)) {
tmpstr[0] = keyPos[i];
strcat(outStr, tmpstr);
outLen++;
Expand All @@ -643,6 +643,10 @@ void readKeyStr(const char *key, char *buffer, int remLength, char *outStr) {
}
} //readKeyStr()

void readKeyStr(const char *key, char *buffer, int remLength, char *outStr) {
readKeyStr(key, buffer, remLength, outStr, kDICOMStrLarge);
} //readKeyStr()

int phoenixOffsetCSASeriesHeader(unsigned char *buff, int lLength) {
//returns offset to ASCII Phoenix data
if (lLength < 36)
Expand Down Expand Up @@ -680,6 +684,7 @@ int phoenixOffsetCSASeriesHeader(unsigned char *buff, int lLength) {
} //phoenixOffsetCSASeriesHeader()

#define kMaxWipFree 64
#define freeDiffusionMaxN 256
typedef struct {
float TE0, TE1, delayTimeInTR, phaseOversampling, phaseResolution, txRefAmp, accelFactTotal;
int lInvContrasts, lContrasts ,phaseEncodingLines, existUcImageNumb, ucMode, baseResolution, interp, partialFourier, echoSpacing,
Expand All @@ -688,6 +693,8 @@ typedef struct {
float adFree[kMaxWipFree];
float alTI[kMaxWipFree];
float sPostLabelingDelay, ulLabelingDuration, dAveragesDouble, dThickness, ulShape, sPositionDTra, sNormalDTra;
int freeDiffusionN;
vec3 freeDiffusionVec[freeDiffusionMaxN];
} TCsaAscii;

void siemensCsaAscii(const char *filename, TCsaAscii *csaAscii, int csaOffset, int csaLength, float *shimSetting, char *coilID, char *consistencyInfo, char *coilElements, char *pulseSequenceDetails, char *fmriExternalInfo, char *protocolName, char *wipMemBlock) {
Expand Down Expand Up @@ -717,7 +724,8 @@ void siemensCsaAscii(const char *filename, TCsaAscii *csaAscii, int csaOffset, i
csaAscii->refLinesPE = 0;
csaAscii->combineMode = 0;
csaAscii->patMode = 0;
csaAscii->ucMTC = 0;
csaAscii->ucMTC = 0;
csaAscii->freeDiffusionN = 0;
for (int i = 0; i < 8; i++)
shimSetting[i] = 0.0;
strcpy(coilID, "");
Expand Down Expand Up @@ -832,7 +840,7 @@ void siemensCsaAscii(const char *filename, TCsaAscii *csaAscii, int csaOffset, i
char keyStrSeq[] = "tSequenceFileName";
readKeyStr(keyStrSeq, keyPos, csaLengthTrim, pulseSequenceDetails);
char keyStrWipMemBlock[] = "sWipMemBlock.tFree";
readKeyStr(keyStrWipMemBlock, keyPos, csaLengthTrim, wipMemBlock);
readKeyStr(keyStrWipMemBlock, keyPos, csaLengthTrim, wipMemBlock, kDICOMStrExtraLarge);
char keyStrPn[] = "tProtocolName";
readKeyStr(keyStrPn, keyPos, csaLengthTrim, protocolName);
char keyStrTE0[] = "alTE[0]";
Expand Down Expand Up @@ -939,6 +947,30 @@ void siemensCsaAscii(const char *filename, TCsaAscii *csaAscii, int csaOffset, i
shimSetting[6] = readKeyFloat(keyStrSh6, keyPos, csaLengthTrim);
char keyStrSh7[] = "sGRADSPEC.alShimCurrent[4]";
shimSetting[7] = readKeyFloat(keyStrSh7, keyPos, csaLengthTrim);

// pull out the directions in the DVI
char keyStrDVIn[] = "sDiffusion.sFreeDiffusionData.lDiffDirections";
int nDiffDir = readKey(keyStrDVIn, keyPos, csaLengthTrim);
csaAscii->freeDiffusionN = min(nDiffDir, freeDiffusionMaxN);

printMessage("Free diffusion: %i\n", csaAscii->freeDiffusionN);

for (int k = 0; k < csaAscii->freeDiffusionN; k++) {
char txt[128];

snprintf(txt, 128, "sDiffusion.sFreeDiffusionData.asDiffDirVector[%i].dSag", k);
float x = readKeyFloat(txt, keyPos, csaLengthTrim);

snprintf(txt, 128, "sDiffusion.sFreeDiffusionData.asDiffDirVector[%i].dCor", k);
float y = readKeyFloat(txt, keyPos, csaLengthTrim);

snprintf(txt, 128, "sDiffusion.sFreeDiffusionData.asDiffDirVector[%i].dTra", k);
float z = readKeyFloat(txt, keyPos, csaLengthTrim);

csaAscii->freeDiffusionVec[k].v[0] = x;
csaAscii->freeDiffusionVec[k].v[1] = y;
csaAscii->freeDiffusionVec[k].v[2] = z;
}
}
free(buffer);
return;
Expand Down Expand Up @@ -1168,7 +1200,7 @@ void rescueProtocolName(struct TDICOMdata *d, const char *filename) {
return;
#ifdef myReadAsciiCsa
float shimSetting[8];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrLarge];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrExtraLarge];
TCsaAscii csaAscii;
siemensCsaAscii(filename, &csaAscii, d->CSA.SeriesHeader_offset, d->CSA.SeriesHeader_length, shimSetting, coilID, consistencyInfo, coilElements, pulseSequenceDetails, fmriExternalInfo, protocolName, wipMemBlock);
if (strlen(protocolName) >= kDICOMStr)
Expand Down Expand Up @@ -1607,7 +1639,7 @@ tse3d: T2*/
if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (d.CSA.SeriesHeader_offset > 0) && (d.CSA.SeriesHeader_length > 0)) {
float pf = 1.0f; //partial fourier
float shimSetting[8];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrLarge];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrExtraLarge];
TCsaAscii csaAscii;
siemensCsaAscii(filename, &csaAscii, d.CSA.SeriesHeader_offset, d.CSA.SeriesHeader_length, shimSetting, coilID, consistencyInfo, coilElements, pulseSequenceDetails, fmriExternalInfo, protocolName, wipMemBlock);
if ((d.phaseEncodingLines < 1) && (csaAscii.phaseEncodingLines > 0))
Expand Down Expand Up @@ -1786,7 +1818,39 @@ tse3d: T2*/
// https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/01-magnetic-resonance-imaging-data.html#common-metadata-fields-applicable-to-both-pcasl-and-pasl
if (((isPASL) || (isPCASL)) && (csaAscii.interp <= 0))
fprintf(fp, "\t\"AcquisitionVoxelSize\": [\n\t\t%g,\n\t\t%g,\n\t\t%g\t],\n", d.xyzMM[1], d.xyzMM[2], d.zThick);
//general properties

// lund free waveform sequence, see https://github.com/filip-szczepankiewicz/fwf_sequence_tools
if ( (strstr(pulseSequenceDetails, "ep2d_diff_fwf") != 0) || (strstr(pulseSequenceDetails, "ep2d_diff_sms_fwf_simple") != 0))
{
for (int i = 0; i < kMaxWipFree; i++) {
if (!isnan(csaAscii.adFree[i]))
fprintf(fp, "\t\"FWF_adFree[%i]\": %g,\n", i, csaAscii.adFree[i]);
}

for (int i = 0; i < kMaxWipFree; i++) {
if (!isnan(csaAscii.alFree[i]))
fprintf(fp, "\t\"FWF_alFree[%i]\": %g,\n", i, csaAscii.alFree[i]);
}

for (int d = 0; d < 3; d++)
{
char str [4096];
strcpy(str, "");
for (int i = 0; i < csaAscii.freeDiffusionN;i++) {
char tmp[10];
snprintf(tmp, 10, "%1.4f", csaAscii.freeDiffusionVec[i].v[d]);
strcat(str, tmp);
if ( (i+1) < csaAscii.freeDiffusionN)
strcat(str, ", ");
}
char dchar = 'x' + d;
fprintf(fp, "\t\"FWF_DVS%c\": [ %s ],\n", dchar, str);
}


}

//general properties
if ((csaAscii.partialFourier > 0) && ((d.modality == kMODALITY_MR))) { //check MR, e.g. do not report for Siemens PET
//https://github.com/ismrmrd/siemens_to_ismrmrd/blob/master/parameter_maps/IsmrmrdParameterMap_Siemens_EPI_FLASHREF.xsl
if (csaAscii.partialFourier == 1)
Expand Down Expand Up @@ -2571,6 +2635,7 @@ int *nii_saveDTI(char pathoutname[], int nConvert, struct TDCMsort dcmSort[], st
fprintf(fp, "\n");
fclose(fp);
#endif

dcmList[indx0].CSA.numDti = numDti; //warning structure not changed outside scope!
geCorrectBvecs(&dcmList[indx0], sliceDir, vx, opts.isVerbose);
siemensPhilipsCorrectBvecs(&dcmList[indx0], sliceDir, vx, opts.isVerbose);
Expand Down Expand Up @@ -6445,7 +6510,7 @@ void setBidsSiemens(struct TDICOMdata *d, int nConvert, int isVerbose, const cha
if ((d->CSA.SeriesHeader_offset > 0) && (d->CSA.SeriesHeader_length > 0)) {
float pf = 1.0f; //partial fourier
float shimSetting[8];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], wipMemBlock[kDICOMStrLarge];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], wipMemBlock[kDICOMStrExtraLarge];
TCsaAscii csaAscii;
siemensCsaAscii(filename, &csaAscii, d->CSA.SeriesHeader_offset, d->CSA.SeriesHeader_length, shimSetting, coilID, consistencyInfo, coilElements, seqDetails, fmriExternalInfo, protocolName, wipMemBlock);
inv1 = csaAscii.alTI[0] / 1000.0;
Expand Down Expand Up @@ -7223,7 +7288,7 @@ void rescueSliceTimingSiemens(struct TDICOMdata *d, int verbose, int nSL, const
return;
#ifdef myReadAsciiCsa
float shimSetting[8];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrLarge];
char protocolName[kDICOMStrLarge], fmriExternalInfo[kDICOMStrLarge], coilID[kDICOMStrLarge], consistencyInfo[kDICOMStrLarge], coilElements[kDICOMStrLarge], pulseSequenceDetails[kDICOMStrLarge], wipMemBlock[kDICOMStrExtraLarge];
TCsaAscii csaAscii;
siemensCsaAscii(filename, &csaAscii, d->CSA.SeriesHeader_offset, d->CSA.SeriesHeader_length, shimSetting, coilID, consistencyInfo, coilElements, pulseSequenceDetails, fmriExternalInfo, protocolName, wipMemBlock);
int ucMode = csaAscii.ucMode;
Expand Down