Skip to content

Commit

Permalink
Detect GE Multi-Band (#336)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Sep 26, 2019
1 parent 325c87b commit b73e1d2
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 10 deletions.
6 changes: 4 additions & 2 deletions FILENAMING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ In general dcm2niix creates images with 3D dimensions, or 4 dimensions when the
- _imaginary imaginary component of complex image
- _real real component of complex image
- _phMag rare case where phase and magnitude are saved as the 4th dimension
- _t If the trigger delay time (0020,9153 or 0018,1060) is non-zero, it will be recorded in the file name. For example, the files "T1_t178.nii" and "T1_t511" suggests that the T1 scan was acquired with two cardiac trigger delays (178 and 511ms after the last R-peak).
- _t If the trigger delay time (0020,9153) is non-zero, it will be recorded in the file name. For example, the files "T1_t178.nii" and "T1_t511" suggests that the T1 scan was acquired with two cardiac trigger delays (178 and 511ms after the last R-peak).
- _ADC Philips specific case. A DWI image where derived isotropic, ADC or trace volume was appended to the series. Since this image will disrupt subsequent processing, and because subsequent processing (dwidenoise, topup, eddy) will yield better derived images, dcm2niix will also create an additional image without this volume. Therefore, the _ADC file should typically be discarded. If you want dcm2niix to discard these useless derived images, use the ignore feature ('-i y').
- _Eq is specific to [CT scans](https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage#Computed_Tomography_.28CT.2C_CAT.29). These scans can be acquired with variable distance between the slices of a 3D volume. NIfTI asumes all 2D slices that form a 3D stack are equidistant. Therefore, dcm2niix reslices the input data to generate an equidistant volume.
- _Tilt is specific to [CT scans](https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage#Computed_Tomography_.28CT.2C_CAT.29). These scans can be acquired with a gantry tilt that causes a skew that can not be stored in a NIfTI qForm. Therefore, the slices are resampled to remove the effect of tilt.
Expand Down Expand Up @@ -64,4 +64,6 @@ dcm2niix will attempt to write your image using the naming scheme you specify wi
| (vertical bar or pipe)
? (question mark)
* (asterisk)
```
```

Be warned that dcm2niix will copy all allowed characters verbatim, which can cause problems for some other tools. Consider this [sample dataset](https://github.com/neurolabusc/dcm_qa_nih/tree/master/In/20180918GE/mr_0004) where the DICOM Protocol Name (0018,1030) is 'Axial_EPI-FMRI_(Interleaved_I_to_S)'. The parentheses ("round brackets") may cause other tools issues. Consider converting this series with the command 'dcm2niix -f %s_%p ~/DICOM' to create the file '4_Axial_EPI-FMRI_(Interleaved_I_to_S).nii'.If you now run the command 'fslhd 4_Axial_EPI-FMRI_(Interleaved_I_to_S).nii' you will get the error '-bash: syntax error near unexpected token `(''. Therefore, it is often a good idea to use double quotes to specify the names of files. In this example 'fslhd "4_Axial_EPI-FMRI_(Interleaved_I_to_S).nii"' will work correctly.
4 changes: 2 additions & 2 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5370,8 +5370,8 @@ double TE = 0.0; //most recent echo time recorded
case kTriggerTime:
//untested method to detect slice timing for GE PSD “epi” with multiphase option
// will not work for current PSD “epiRT” (BrainWave RT, fMRI/DTI package provided by Medical Numerics)
if (d.manufacturer != kMANUFACTURER_GE) break;
d.triggerDelayTime = dcmStrFloat(lLength, &buffer[lPos]);
if (d.manufacturer != kMANUFACTURER_GE) break;
d.triggerDelayTime = dcmStrFloat(lLength, &buffer[lPos]); //???? issue 336
d.CSA.sliceTiming[acquisitionTimesGE_UIH] = d.triggerDelayTime;
//printf("%g\n", d.CSA.sliceTiming[acquisitionTimesGE_UIH]);
acquisitionTimesGE_UIH ++;
Expand Down
2 changes: 1 addition & 1 deletion console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ extern "C" {
#define kCCsuf " CompilerNA" //unknown compiler!
#endif

#define kDCMdate "v1.0.20190910"
#define kDCMdate "v1.0.20190926"
#define kDCMvers kDCMdate " " kJP2suf kLSsuf kCCsuf

static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens Mosaic
Expand Down
21 changes: 16 additions & 5 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ void siemensCsaAscii(const char * filename, TCsaAscii* csaAscii, int csaOffset,
#define myReadGeProtocolBlock
#endif
#ifdef myReadGeProtocolBlock
int geProtocolBlock(const char * filename, int geOffset, int geLength, int isVerbose, int* sliceOrder, int* viewOrder) {
int geProtocolBlock(const char * filename, int geOffset, int geLength, int isVerbose, int* sliceOrder, int* viewOrder, int* mbAccel) {
*sliceOrder = -1;
*viewOrder = 0;
int ret = EXIT_FAILURE;
Expand Down Expand Up @@ -836,8 +836,10 @@ int geProtocolBlock(const char * filename, int geOffset, int geLength, int isV
printWarning("New XML-based GE Protocol Block is not yet supported: please report issue on dcm2niix Github page\n");
char keyStrSO[] = "SLICEORDER";
*sliceOrder = readKeyN1(keyStrSO, (char *) pUnCmp, unCmpSz);
char keyStrVO[] = "VIEWORDER"; //"MATRIXX";
char keyStrVO[] = "VIEWORDER";
*viewOrder = readKey(keyStrVO, (char *) pUnCmp, unCmpSz);
char keyStrMB[] = "MBACCEL";
*mbAccel = readKey(keyStrMB, (char *) pUnCmp, unCmpSz);
if (isVerbose > 1) {
printMessage("GE Protocol Block %s bytes %d compressed, %d uncompressed @ %d\n", filename, geLength, unCmpSz, geOffset);
printMessage(" ViewOrder %d SliceOrder %d\n", *viewOrder, *sliceOrder);
Expand Down Expand Up @@ -2368,7 +2370,7 @@ int nii_createFilename(struct TDICOMdata dcm, char * niiFilename, struct TDCMopt
if (dcm.isHasMagnitude)
strcat (outname,"Mag"); //Philips enhanced with BOTH phase and Magnitude in single file
}
if (dcm.triggerDelayTime >= 1) {
if ((dcm.triggerDelayTime >= 1) && (dcm.manufacturer != kMANUFACTURER_GE)){ //issue 336 GE uses this for slice timing
sprintf(newstr, "_t%d", (int)roundf(dcm.triggerDelayTime));
strcat (outname,newstr);
}
Expand Down Expand Up @@ -4236,7 +4238,6 @@ void rescueSliceTimingGE(struct TDICOMdata * d, int verbose, int nSL, const char
// if both of these methods fail, we can often guess based on slice order stored in the Private Protocol Data Block (0025,101B)
// this is referred to as "rescue" as we only know the TR, not the TA. So assumes continuous scans with no gap
if (d->is3DAcq) return; //no need for slice times
if (d->CSA.sliceTiming[0] >= 0.0) return; //slice times calculated
if (nSL < 2) return;
if (d->manufacturer != kMANUFACTURER_GE) return;
if ((d->protocolBlockStartGE < 1) || (d->protocolBlockLengthGE < 19)) return;
Expand All @@ -4247,12 +4248,22 @@ void rescueSliceTimingGE(struct TDICOMdata * d, int verbose, int nSL, const char
// Therefore, we warning the user that we are guessing
int viewOrderGE = -1;
int sliceOrderGE = -1;
int mbAccel = -1;
//printWarning("Using GE Protocol Data Block for BIDS data (beware: new feature)\n");
int ok = geProtocolBlock(filename, d->protocolBlockStartGE, d->protocolBlockLengthGE, verbose, &sliceOrderGE, &viewOrderGE);
int ok = geProtocolBlock(filename, d->protocolBlockStartGE, d->protocolBlockLengthGE, verbose, &sliceOrderGE, &viewOrderGE, &mbAccel);
if (ok != EXIT_SUCCESS) {
printWarning("Unable to decode GE protocol block\n");
return;
}
if (mbAccel > 1) {
d->CSA.multiBandFactor = mbAccel;
printWarning("Unabled to compute slice times for GE multi-band. SliceOrder=%d (seq=0, int=1)\n", sliceOrderGE);
d->CSA.sliceTiming[0] = -1.0;
return;

}
if (d->CSA.sliceTiming[0] >= 0.0) return; //slice times calculated - moved here to detect multiband, see issue 336

if ((sliceOrderGE < 0) || (sliceOrderGE > 1)) return;
// 0=sequential/1=interleaved
printWarning("Guessing slice times using ProtocolBlock SliceOrder=%d (seq=0, int=1)\n", sliceOrderGE);
Expand Down

0 comments on commit b73e1d2

Please sign in to comment.