Skip to content

Commit

Permalink
Explicit exit code for missing input/output folder (https://discourse…
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Sep 21, 2019
1 parent 0736d6c commit 325c87b
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Philips/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ MyCustomDirections

Philips DICOMs do not contain all the information desired by many neuroscientists. Due to this, the [BIDS](http://bids.neuroimaging.io/) files created by dcm2niix are impoverished relative to data from other vendors. This reflects a limitation in the Philips DICOMs, not dcm2niix.

[Slice timing correction](https://www.mccauslandcenter.sc.edu/crnl/tools/stc) can account for some variability in fMRI datasets. Unfortunately, Philips DICOM data [does not encode slice timing information](https://neurostars.org/t/heudiconv-no-extraction-of-slice-timing-data-based-on-philips-dicoms/2201/4). Therefore, dcm2niix is unable to populate the "SliceTiming" BIDS field. However, one can typically infer slice timing by recording the [mode and number of packages](https://en.wikibooks.org/w/index.php?title=SPM/Slice_Timing&stable=0#Philips_scanners) reported for the sequence on the scanner console.
[Slice timing correction](https://www.mccauslandcenter.sc.edu/crnl/tools/stc) can account for some variability in fMRI datasets. Unfortunately, Philips DICOM data [does not encode slice timing information](https://neurostars.org/t/heudiconv-no-extraction-of-slice-timing-data-based-on-philips-dicoms/2201/4). Therefore, dcm2niix is unable to populate the "SliceTiming" BIDS field. However, one can typically infer slice timing by recording the [mode and number of packages](https://en.wikibooks.org/w/index.php?title=SPM/Slice_Timing&stable=0#Philips_scanners) reported for the sequence on the scanner console or the [sequence PDF](http://adni.loni.usc.edu/wp-content/uploads/2017/09/ADNI-3-Basic-Philips-R5.pdf). For precise timing, it is also worth knowing if equidistant "temporal slice spacing" is set and whether "prospect. motion corr." is on or off (if on, a short delay occurs between volumes).

Likewise, the BIDS tag "PhaseEncodingDirection" allows tools like [eddy](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/eddy) and [TOPUP](https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/topup) to undistort images. While the Philips DICOM header distinguishes the phase encoding axis (e.g. anterior-posterior vs left-right) it does not encode the polarity (A->P vs P->A).

Expand Down
2 changes: 2 additions & 0 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4048,6 +4048,8 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
#define kDirectoryRecordSequence 0x0004+(0x1220 << 16 )
//#define kSpecificCharacterSet 0x0008+(0x0005 << 16 ) //someday we should handle foreign characters...
#define kImageTypeTag 0x0008+(0x0008 << 16 )
//#define kSOPInstanceUID 0x0008+(0x0018 << 16 ) //Philips inserts time as last item, e.g. ?.?.?.YYYYMMDDHHmmSS.SSSS
// not reliable https://neurostars.org/t/heudiconv-no-extraction-of-slice-timing-data-based-on-philips-dicoms/2201/21
#define kStudyDate 0x0008+(0x0020 << 16 )
#define kAcquisitionDate 0x0008+(0x0022 << 16 )
#define kAcquisitionDateTime 0x0008+(0x002A << 16 )
Expand Down
4 changes: 4 additions & 0 deletions console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ static const int kMaxSlice2D = 64000; //maximum number of 2D slices in 4D (Phili
#define kEXIT_NO_VALID_FILES_FOUND 2
#define kEXIT_REPORT_VERSION 3
#define kEXIT_CORRUPT_FILE_FOUND 4
#define kEXIT_INPUT_FOLDER_INVALID 5
#define kEXIT_OUTPUT_FOLDER_INVALID 6
#define kEXIT_OUTPUT_FOLDER_READ_ONLY 7

static const int kSliceOrientUnknown = 0;
static const int kSliceOrientTra = 1;
static const int kSliceOrientSag = 2;
Expand Down
30 changes: 29 additions & 1 deletion console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2159,6 +2159,8 @@ int nii_createFilename(struct TDICOMdata dcm, char * niiFilename, struct TDCMopt
strcpy(pth, opts.outdir);
int w =access(pth,W_OK);
if (w != 0) {
//should never happen except with "-b i": see kEXIT_OUTPUT_FOLDER_READ_ONLY for early termination
// with "-b i" the code below generates a warning but no files are created
if (getcwd(pth, sizeof(pth)) != NULL) {
#ifdef USE_CWD_IF_OUTDIR_NO_WRITE //optional: fall back to current working directory
w =access(pth,W_OK);
Expand Down Expand Up @@ -4462,6 +4464,7 @@ void sliceTimingGE(struct TDCMsort *dcmSort,struct TDICOMdata *dcmList, struct n

int sliceTimingCore(struct TDCMsort *dcmSort,struct TDICOMdata *dcmList, struct nifti_1_header * hdr, int verbose, const char * filename, int nConvert) {
int sliceDir = 0;
if (hdr->dim[3] < 2) return sliceDir;
//uint64_t indx0 = dcmSort[0].indx;
//uint64_t indx1 = dcmSort[1].indx;
struct TDICOMdata * d0 = &dcmList[dcmSort[0].indx];
Expand Down Expand Up @@ -6072,6 +6075,11 @@ int nii_loadDir(struct TDCMopts* opts) {
if (isFile) //if user passes ~/dicom/mr1.dcm we will look at all files in ~/dicom
dropFilenameFromPath(opts->indir);
dropTrailingFileSep(opts->indir);
if (!is_dir(opts->indir,true)) {
printError("Input folder invalid: %s\n",opts->indir);
return kEXIT_INPUT_FOLDER_INVALID;
}

#ifdef USING_R
// Full file paths are only used by R/divest when reorganising DICOM files
if (opts->isRenameNotConvert) {
Expand All @@ -6086,9 +6094,29 @@ int nii_loadDir(struct TDCMopts* opts) {
strcpy(opts->outdir,opts->indir);
#else
printError("Output folder invalid: %s\n",opts->outdir);
return EXIT_FAILURE;
return kEXIT_OUTPUT_FOLDER_INVALID;
#endif
}
//check file permissions
if ((opts->isCreateBIDS != false) || (opts->isOnlyBIDS != true)) { //output files expected: either BIDS or images
int w =access(opts->outdir,W_OK);
if (w != 0) {
#ifdef USE_CWD_IF_OUTDIR_NO_WRITE
char outdir[512];
strcpy(outdir,opts->outdir);
strcpy(opts->outdir,opts->indir);
w =access(opts->outdir,W_OK);
if (w != 0) {
printError("Unable to write to output folder: %s\n",outdir);
return kEXIT_OUTPUT_FOLDER_READ_ONLY;
} else
printWarning("Writing to working directory, unable to write to output folder: %s\n",outdir);
#else
printError("Unable to write to output folder: %s\n",opts->outdir);
return kEXIT_OUTPUT_FOLDER_READ_ONLY;
#endif
}
}
#ifdef USING_R
}
#endif
Expand Down

0 comments on commit 325c87b

Please sign in to comment.