Skip to content

Commit

Permalink
PRs (#745; #768)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Dec 17, 2023
1 parent 3c7f26b commit b040b44
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ The following tools exploit dcm2niix
- [dicom2nifti_batch](https://github.com/scanUCLA/dicom2nifti_batch) is a Matlab script for automating dcm2niix.
- [dicomConversionToNifti](https://github.com/bsmarine/dicomConversionToNifti) converts, de-identifies and assigns standardized naming convention to medical imaging.
- [divest](https://github.com/jonclayden/divest) R interface to dcm2niix.
- [DPABI Data Processing & Analysis for Brain Imaging](http://rfmri.org/dpabi) includes dcm2niix.
- [DPABI](https://github.com/Chaogan-Yan/DPABI) [Data Processing & Analysis for Brain Imaging](https://rfmri.org/DPABI) includes dcm2niix.
- [ExploreASL](https://sites.google.com/view/exploreasl/exploreasl) uses dcm2niix to import images.
- [ExploreASL-GUI](https://github.com/MauricePasternak/ExploreASL-GUI) uses dcm2niix for image conversion.
- [ezBIDS](https://github.com/brainlife/ezbids) is a [web service](https://brainlife.io/ezbids/) for converting directory full of DICOM images into BIDS without users having to learn python nor custom configuration file.
Expand Down
2 changes: 1 addition & 1 deletion RENAMING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dcm2niix is primarily designed to convert DICOM images into NIfTI images. Howeve

## Limitation

dcm2niix renames and copies the DICOM images, but the current version does not copy or create a new [DICOMDIR](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_F.2.2.2.html) file. Most users ignore these files. However, you should not use this featire if you wish to preserve your DICOMDIR files.
dcm2niix renames and copies the DICOM images, but the current version does not copy or create a new [DICOMDIR](http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_F.2.2.2.html) file. Most users ignore these files. However, you should not use this feature if you wish to preserve your DICOMDIR files.

Note that this feature only copies your DICOM images with a new filename. It does not modify the contents of the DICOM header. This means it will not compress or anonymize your files. Free tools for these functions include [dcmcjpeg](https://dicom.offis.de/dcmtk.php.en), [gdcmanon](http://gdcm.sourceforge.net/html/gdcmanon.html) and [gdcmconv](http://gdcm.sourceforge.net/html/gdcmconv.html).

Expand Down
1 change: 1 addition & 0 deletions console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ 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
73 changes: 65 additions & 8 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 readKeyStrLen(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) {
readKeyStrLen(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,14 +684,16 @@ int phoenixOffsetCSASeriesHeader(unsigned char *buff, int lLength) {
} //phoenixOffsetCSASeriesHeader()

#define kMaxWipFree 64
#define freeDiffusionMaxN 512
typedef struct {
float TE0, TE1, delayTimeInTR, phaseOversampling, phaseResolution, txRefAmp, accelFactTotal;
int lInvContrasts, lContrasts ,phaseEncodingLines, existUcImageNumb, ucMode, baseResolution, interp, partialFourier, echoSpacing,
difBipolar, parallelReductionFactorInPlane, refLinesPE, combineMode, patMode, ucMTC, accelFact3D;
difBipolar, parallelReductionFactorInPlane, refLinesPE, combineMode, patMode, ucMTC, accelFact3D, freeDiffusionN;
float alFree[kMaxWipFree];
float adFree[kMaxWipFree];
float alTI[kMaxWipFree];
float sPostLabelingDelay, ulLabelingDuration, dAveragesDouble, dThickness, ulShape, sPositionDTra, sNormalDTra;
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 @@ -718,6 +724,7 @@ void siemensCsaAscii(const char *filename, TCsaAscii *csaAscii, int csaOffset, i
csaAscii->combineMode = 0;
csaAscii->patMode = 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 +839,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);
readKeyStrLen(keyStrWipMemBlock, keyPos, csaLengthTrim, wipMemBlock, kDICOMStrExtraLarge);
char keyStrPn[] = "tProtocolName";
readKeyStr(keyStrPn, keyPos, csaLengthTrim, protocolName);
char keyStrTE0[] = "alTE[0]";
Expand Down Expand Up @@ -939,6 +946,29 @@ 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 +1198,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 @@ -1615,7 +1645,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 @@ -1802,6 +1832,33 @@ 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);
// 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
Expand Down Expand Up @@ -6509,7 +6566,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 @@ -7331,7 +7388,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

0 comments on commit b040b44

Please sign in to comment.