Skip to content

Commit

Permalink
detect Siemens Phase maps
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Apr 22, 2016
1 parent 8e8ff5f commit 31c59d8
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 21 deletions.
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,40 @@ dcm2niix is a designed to convert neuroimaging data from the DICOM format to the

## Versions

22-Apr-2016
- Detect Siemens Phase maps (phase image names end with "_ph").
- Use current working directory if file name not specified.

12-Apr-2016
- Provide override (command line option "-m y") to stack images of the same series even if they differ in study date/time, echo/coil number, or slice orientation. This mechanism allows users to concatenate images that break strict DICOM compliance.

22-Mar-2016
- Experimental support for [http://dicom.nema.org/dicom/2013/output/chtml/part10/chapter_7.html DICOM dataset's without DICOM file meta information].

12-Dec-2015
- Support PAR/REC FP values when possible(see PMC3998685)
- Support PAR/REC FP values when possible(see PMC3998685).

11-Nov-2015
- Minor refinements
- Minor refinements.

12-June-2015
- Uses less memory (helpful for large datasets)
- Uses less memory (helpful for large datasets).

2-Feb-2015
- Support for Visual Studio
- Remove dependency on zlib (now uses miniz)
- Support for Visual Studio.
- Remove dependency on zlib (now uses miniz).

1-Jan-2015
- Images separated based on TE (fieldmaps)
- Support for JPEG2000 using OpenJPEG or Jasper libraries
- Support for JPEG using NanoJPEG library
- Support for lossless JPEG using custom library
- Images separated based on TE (fieldmaps).
- Support for JPEG2000 using OpenJPEG or Jasper libraries.
- Support for JPEG using NanoJPEG library.
- Support for lossless JPEG using custom library.

24-Nov-2014
- Support for CT scans with gantry tilt and varying distance between slices
- Support for CT scans with gantry tilt and varying distance between slices.

11-Oct-2014
- Initial public release
- Initial public release.

## Running

Expand Down
37 changes: 35 additions & 2 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,8 @@ struct TDICOMdata clear_dicom_data() {
d.CSA.slice_end = 0;
d.CSA.protocolSliceNumber1 = 0;
d.CSA.phaseEncodingDirectionPositive = -1; //unknown
d.CSA.isPhaseMap = false;
d.CSA.multiBandFactor = 1;
return d;
} //clear_dicom_data()

Expand Down Expand Up @@ -909,6 +911,33 @@ float csaMultiFloat (unsigned char buff[], int nItems, float Floats[], int *Item
return Floats[1];
} //csaMultiFloat()

bool csaIsPhaseMap (unsigned char buff[], int nItems) {
//returns true if the tag "ImageHistory" has an item named "CC:ComplexAdd"
TCSAitem itemCSA;
if (nItems < 1) return false;
int lPos = 0;
for (int lI = 1; lI <= nItems; lI++) {
memcpy(&itemCSA, &buff[lPos], sizeof(itemCSA));
lPos +=sizeof(itemCSA);
if (itemCSA.xx2_Len > 0) {
#ifdef _MSC_VER
char * cString = (char *)malloc(sizeof(char) * (itemCSA.xx2_Len));
#else
char cString[itemCSA.xx2_Len];
#endif
memcpy(cString, &buff[lPos], sizeof(cString)); //TPX memcpy(&cString, &buff[lPos], sizeof(cString));
lPos += ((itemCSA.xx2_Len +3)/4)*4;
//printf(" %d item length %d = %s\n",lI, itemCSA.xx2_Len, cString);
if (strcmp(cString, "CC:ComplexAdd") == 0)
return true;
#ifdef _MSC_VER
free(cString);
#endif
}
} //for each item
return false;
} //csaIsPhaseMap()

int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, int isVerbose, struct TDTI4D *dti4D) {
//see also http://afni.nimh.nih.gov/pub/dist/src/siemens_dicom_csa.c
//printf("%c%c%c%c\n",buff[0],buff[1],buff[2],buff[3]);
Expand All @@ -925,9 +954,12 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
for (int lT = 1; lT <= lnTag; lT++) {
memcpy(&tagCSA, &buff[lPos], sizeof(tagCSA)); //read tag
lPos +=sizeof(tagCSA);
//printf("%d CSA of %s %d\n",lPos, tagCSA.name, tagCSA.nitems);
if (isVerbose > 1) //extreme verbosity: show every CSA tag
printf("%d CSA of %s %d\n",lPos, tagCSA.name, tagCSA.nitems);
if (tagCSA.nitems > 0) {
if (strcmp(tagCSA.name, "NumberOfImagesInMosaic") == 0)
if (strcmp(tagCSA.name, "ImageHistory") == 0)
CSA->isPhaseMap = csaIsPhaseMap(&buff[lPos], tagCSA.nitems);
else if (strcmp(tagCSA.name, "NumberOfImagesInMosaic") == 0)
CSA->mosaicSlices = (int) round(csaMultiFloat (&buff[lPos], 1,lFloats, &itemsOK));
else if (strcmp(tagCSA.name, "B_value") == 0) {
CSA->dtiV[0] = csaMultiFloat (&buff[lPos], 1,lFloats, &itemsOK);
Expand Down Expand Up @@ -2840,6 +2872,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
break;
case kCSAImageHeaderInfo:
readCSAImageHeader(&buffer[lPos], lLength, &d.CSA, isVerbose, dti4D);
d.isHasPhase = d.CSA.isPhaseMap;
break;
//case kObjectGraphics:
// printf("---->%d,",lLength);
Expand Down
7 changes: 4 additions & 3 deletions console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ extern "C" {
#endif

#ifdef myEnableJasper
#define kDCMvers "12Apr2016j" //JASPER for JPEG2000
#define kDCMvers "22Apr2016j" //JASPER for JPEG2000
#else
#ifdef myDisableOpenJPEG
#define kDCMvers "12Apr2016" //no decompressor
#define kDCMvers "22Apr2016" //no decompressor
#else
#define kDCMvers "12Apr2016o" //OPENJPEG for JPEG2000
#define kDCMvers "22Apr2016o" //OPENJPEG for JPEG2000
#endif
#endif

Expand Down Expand Up @@ -45,6 +45,7 @@ static const int kCompress50 = 3; //obsolete JPEG lossy
};

struct TCSAdata {
bool isPhaseMap;
float dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
int numDti, multiBandFactor, sliceOrder, slice_start, slice_end, mosaicSlices,protocolSliceNumber1,phaseEncodingDirectionPositive;
};
Expand Down
16 changes: 11 additions & 5 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ void dropFilenameFromPath(char *path) { //
strcpy(path,"");
} else
path[dirPath - path] = 0; // please make sure there is enough space in TargetDirectory
if (strlen(path) == 0) strcat (path,"."); //relative path - use cwd
}


Expand Down Expand Up @@ -715,14 +716,16 @@ int nii_createFilename(struct TDICOMdata dcm, char * niiFilename, struct TDCMopt
} //found a % character
pos++;
} //for each character in input
if (dcm.echoNum > 1) {
if (dcm.coilNum > 1) {
sprintf(newstr, "_c%d", dcm.coilNum);
strcat (outname,newstr);
}
if (dcm.echoNum > 1) {
sprintf(newstr, "_%d", dcm.echoNum);
sprintf(newstr, "_e%d", dcm.echoNum);
strcat (outname,newstr);
}
if (dcm.isHasPhase)
strcat (outname,"_ph"); //manufacturer name not available
if (pos > start) { //append any trailing characters
strncpy(&newstr[0], &inname[0] + start, pos - start);
newstr[pos - start] = '\0';
Expand Down Expand Up @@ -1413,8 +1416,12 @@ bool isSameSet (struct TDICOMdata d1, struct TDICOMdata d2, bool isForceStackSam
printf("slices not stacked: Study Data/Time (0008,0020 / 0008,0030) varies %12.12f ~= %12.12f\n", d1.dateTime, d2.dateTime);
return false;
}
if ((d1.TE != d2.TE) || (d1.coilNum != d2.coilNum) || (d1.echoNum != d2.echoNum)) {
printf("filse not stacked: echo or coil varies\n");
if ((d1.TE != d2.TE) || (d1.echoNum != d2.echoNum)) {
printf("slices not stacked: echo varies (TE %g, %g; echo %d, %d)\n", d1.TE, d2.TE,d1.echoNum, d2.echoNum );
return false;
}
if (d1.coilNum != d2.coilNum) {
printf("slices not stacked: coil varies\n");
return false;
}
if (strcmp(d1.protocolName, d2.protocolName) != 0) {
Expand Down Expand Up @@ -1790,7 +1797,6 @@ int nii_loadDir (struct TDCMopts* opts) {
return convert_foreign(*opts);
}*/
getFileName(opts->indirParent, opts->indir);
//printf("XXXXXXX %s\n XXX\n", opts->indirParent); return EXIT_FAILURE;
if (isFile && ((isExt(indir, ".par")) || (isExt(indir, ".rec"))) ) {
char pname[512], rname[512];
strcpy(pname,indir);
Expand Down

0 comments on commit 31c59d8

Please sign in to comment.