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

DCM2NIIXFSLIB changes #800

Merged
merged 1 commit into from
Feb 28, 2024
Merged
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
138 changes: 131 additions & 7 deletions console/dcm2niix_fswrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>

#include "nii_dicom.h"
Expand Down Expand Up @@ -53,15 +54,13 @@ numSeries = 0
*/

// set TDCMopts defaults, overwrite settings to output in mgz orientation
void dcm2niix_fswrapper::setOpts(const char* dcmindir, const char* niioutdir, bool createBIDS, int ForceStackSameSeries)
void dcm2niix_fswrapper::setOpts(const char* dcmindir, const char* dcm2niixopts)
{
memset(&tdcmOpts, 0, sizeof(tdcmOpts));
setDefaultOpts(&tdcmOpts, NULL);

if (dcmindir != NULL)
strcpy(tdcmOpts.indir, dcmindir);
if (niioutdir != NULL)
strcpy(tdcmOpts.outdir, niioutdir);

// dcmunpack actually uses seriesDescription, set FName = `printf %04d.$descr $series`
// change it from "%4s.%p" to "%4s.%d"
Expand All @@ -71,11 +70,136 @@ void dcm2niix_fswrapper::setOpts(const char* dcmindir, const char* niioutdir, bo
tdcmOpts.isRotate3DAcq = false;
tdcmOpts.isFlipY = false;
tdcmOpts.isIgnoreSeriesInstanceUID = true;
tdcmOpts.isCreateBIDS = createBIDS;
tdcmOpts.isCreateBIDS = false;
tdcmOpts.isGz = false;
tdcmOpts.isForceStackSameSeries = ForceStackSameSeries; // merge 2D slice '-m y', tdcmOpts.isForceStackSameSeries = 1
tdcmOpts.isForceStackSameSeries = 1; // merge 2D slice '-m y', tdcmOpts.isForceStackSameSeries = 1
tdcmOpts.isForceStackDCE = false;
//tdcmOpts.isForceOnsetTimes = false;

if (dcm2niixopts != NULL)
__setDcm2niixOpts(dcm2niixopts);
}

/* set user dcm2niix conversion options in struct TDCMopts tdcmOpts
* only subset of dcm2niix command line options are recognized: (https://manpages.ubuntu.com/manpages/jammy/en/man1/dcm2niix.1.html)
* -b <y/i/n>
* Save additional BIDS metadata to a side-car .json file (default y).
* The "i"nput-only option reads DICOMs but saves neither BIDS nor NIfTI.
*
* -ba <y/n> anonymize BIDS (default y).
* If "n"o, side-car may report patient name, age and weight.
*
* -f <format>
* Format string for the output filename(s).
*
* -i <y/n>
* Ignore derived, localizer and 2D images (default n)
*
* -m <y/n/2>
* Merge slices from the same series regardless of study time, echo, coil, orientation, etc. (default 2).
* If "2", automatic based on image modality.
*
* -v <2/y/n>
* Enable verbose output. "n" for succinct, "y" for verbose, "2" for high verbosity
*
* -o <path>
* Output directory where the converted files should be saved.
*
* -t <y/n>
* Save patient details as text notes.
*
* -p <y/n>
* Use Philips precise float (rather than display) scaling.
*
* -x <y/n/i>
* Crop images. This will attempt to remove excess neck from 3D acquisitions.
* If "i", images are neither cropped nor rotated to canonical space.
*/
void dcm2niix_fswrapper::__setDcm2niixOpts(const char *dcm2niixopts)
{
//printf("[DEBUG] dcm2niix_fswrapper::__setDcm2niixOpts(%s)\n", dcm2niixopts);

char *restOpts = (char*)malloc(strlen(dcm2niixopts)+1);
memset(restOpts, 0, strlen(dcm2niixopts)+1);
memcpy(restOpts, dcm2niixopts, strlen(dcm2niixopts));

char *nextOpt = strtok_r((char*)dcm2niixopts, ",", &restOpts);
while (nextOpt != NULL)
{
char *k = nextOpt;
char *v = strchr(nextOpt, '=');
if (v != NULL)
*v = '\0';
v++; // move past '='

// skip leading white spaces
while (*k == ' ')
k++;

if (strcmp(k, "b") == 0)
{
if (*v == 'n' || *v == 'N' || *v == '0')
tdcmOpts.isCreateBIDS = false;
else if (*v == 'i' || *v == 'I')
{
tdcmOpts.isCreateBIDS = false;
tdcmOpts.isOnlyBIDS = true;
}
else if (*v == 'y' || *v == 'Y')
tdcmOpts.isCreateBIDS = true;
}
else if (strcmp(k, "ba") == 0)
tdcmOpts.isAnonymizeBIDS = (*v == 'n' || *v == 'N') ? false : true;
else if (strcmp(k, "f") == 0)
strcpy(tdcmOpts.filename, v);
else if (strcmp(k, "i") == 0)
tdcmOpts.isIgnoreDerivedAnd2D = (*v == 'y' || *v == 'Y') ? true : false;
else if (strcmp(k, "m") == 0)
{
if (*v == 'n' || *v == 'N' || *v == '0')
tdcmOpts.isForceStackSameSeries = 0;
else if (*v == 'y' || *v == 'Y' || *v == '1')
tdcmOpts.isForceStackSameSeries = 1;
else if (*v == '2')
tdcmOpts.isForceStackSameSeries = 2;
else if (*v == 'o' || *v == 'O')
tdcmOpts.isForceStackDCE = false;
}
else if (strcmp(k, "v") == 0)
{
if (*v == 'n' || *v == 'N' || *v == '0')
tdcmOpts.isVerbose = 0;
else if (*v == 'h' || *v == 'H' || *v == '2')
tdcmOpts.isVerbose = 2;
else
tdcmOpts.isVerbose = 1;
}
else if (strcmp(k, "o") == 0)
strcpy(tdcmOpts.outdir, v);
else if (strcmp(k, "t") == 0)
tdcmOpts.isCreateText = (*v == 'y' || *v == 'Y') ? true : false;
else if (strcmp(k, "p") == 0)
{
if (*v == 'n' || *v == 'N' || *v == '0')
tdcmOpts.isPhilipsFloatNotDisplayScaling = false;
}
else if (strcmp(k, "x") ==0)
{
if (*v == 'y' || *v == 'Y')
tdcmOpts.isCrop = true;
else if (*v == 'i' || *v == 'I')
{
tdcmOpts.isRotate3DAcq = false;
tdcmOpts.isCrop = false;
}
}
else
{
printf("[WARN] dcm2niix option %s=%s skipped\n", k, v);
}

nextOpt = strtok_r(NULL, ",", &restOpts);
}
}

// interface to isDICOMfile() in nii_dicom.cpp
Expand Down Expand Up @@ -157,10 +281,10 @@ void dcm2niix_fswrapper::dicomDump(const char* dicomdir, const char *series_info
fclose(fp_dcmLst);

// output series_info
fprintf(fpout, "%ld %s %f %f %f %f\\%f %c %f %s %s",
fprintf(fpout, "%ld %s %f %f %f %f\\%f %c %f %s %s %s",
tdicomData->seriesNum, tdicomData->seriesDescription,
tdicomData->TE, tdicomData->TR, tdicomData->flipAngle, tdicomData->xyzMM[1], tdicomData->xyzMM[2],
tdicomData->phaseEncodingRC, tdicomData->pixelBandwidth, (*mrifsStruct_vector)[n].dicomfile, tdicomData->imageType);
tdicomData->phaseEncodingRC, tdicomData->pixelBandwidth, (*mrifsStruct_vector)[n].dicomfile, tdicomData->imageType, (*mrifsStruct_vector)[n].pulseSequenceDetails);
#if 0
if (max)
{
Expand Down
5 changes: 4 additions & 1 deletion console/dcm2niix_fswrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class dcm2niix_fswrapper
{
public:
// set TDCMopts defaults, overwrite settings to output in mgz orientation.
static void setOpts(const char* dcmindir, const char* niioutdir=NULL, bool createBIDS=false, int ForceStackSameSeries=1);
static void setOpts(const char* dcmindir, const char* dcm2niixopts=NULL);

// interface to isDICOMfile() in nii_dicom.cpp
static bool isDICOM(const char* file);
Expand Down Expand Up @@ -47,6 +47,9 @@ class dcm2niix_fswrapper

private:
static struct TDCMopts tdcmOpts;

//
static void __setDcm2niixOpts(const char *dcm2niixopts);
};

#endif
21 changes: 20 additions & 1 deletion console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8342,6 +8342,19 @@ 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 @@ -10008,10 +10021,16 @@ 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]));

printMessage("%s %ld %s %s %f %f %f %f\\%f %c %f %s %s\n",
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",
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
1 change: 1 addition & 0 deletions console/nii_dicom_batch.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct MRIFSSTRUCT
size_t imgsz;
unsigned char *imgM;

char pulseSequenceDetails[kDICOMStr];
struct TDICOMdata tdicomData;
char namePostFixes[256];
char *dicomfile;
Expand Down
Loading