Skip to content

Commit

Permalink
Patch for alternative gantry tilt detection (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Dec 29, 2018
1 parent 73a1dcb commit 8561c3e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 5 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@ If you have any problems with the cmake build script described above or want to
- [MRtrix mrconvert](http://mrtrix.readthedocs.io/en/latest/reference/commands/mrconvert.html) is a useful general purpose image converter and handles DTI data well. It is an outstanding tool for modern Philips enhanced images.
- [mcverter](http://lcni.uoregon.edu/%7Ejolinda/MRIConvert/) has great support for various vendors.
- [mri_convert](https://surfer.nmr.mgh.harvard.edu/pub/docs/html/mri_convert.help.xml.html) is part of the popular FreeSurfer package. In my limited experience this tool works well for GE and Siemens data, but fails with Philips 4D datasets.
- [Plastimatch](https://www.plastimatch.org/) is a Swiss Army knife - it computes registration, image processing, statistics and it has a basiccor image format converter that can convert many DICOM images to NIfTI.
- [SPM12](http://www.fil.ion.ucl.ac.uk/spm/software/spm12/) is one of the most popular tools in the field. It includes DICOM to NIfTI conversion. Being based on Matlab it is easy to script.

## Links

- [bidsify](https://github.com/spinoza-rec/bidsify) is a Python project that uses dcm2niix to convert DICOM and Philips PAR/REC images to the BIDS standard.
- [bidskit](https://github.com/jmtyszka/bidskit) uses dcm2niix to create [BIDS](http://bids.neuroimaging.io/) datasets.
- [bidskit](https://github.com/jmtyszka/bidskit) uses dcm2niix t
o create [BIDS](http://bids.neuroimaging.io/) datasets.
- [boutiques-dcm2niix](https://github.com/lalet/boutiques-dcm2niix) is a dockerfile for installing and validating dcm2niix.
- [DAC2BIDS](https://github.com/dangom/dac2bids) uses dcm2niibatch to create [BIDS](http://bids.neuroimaging.io/) datasets.
- [Dcm2Bids](https://github.com/cbedetti/Dcm2Bids) uses dcm2niix to create [BIDS](http://bids.neuroimaging.io/) datasets.
Expand Down
31 changes: 27 additions & 4 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2416,6 +2416,10 @@ void nii_check16bitUnsigned(unsigned char *img, struct nifti_1_header *hdr, int
}
#endif

//void reportPos(struct TDICOMdata d1) {
// printMessage("Instance\t%d\t0020,0032\t%g\t%g\t%g\n", d1.imageNum, d1.patientPosition[1],d1.patientPosition[2],d1.patientPosition[3]);
//}

int siemensCtKludge(int nConvert, struct TDCMsort dcmSort[],struct TDICOMdata dcmList[]) {
//Siemens CT bug: when a user draws an open object graphics object onto a 2D slice this is appended as an additional image,
//regardless of slice position. These images do not report number of positions in the volume, so we need tedious leg work to detect
Expand All @@ -2425,6 +2429,8 @@ int siemensCtKludge(int nConvert, struct TDCMsort dcmSort[],struct TDICOMdata dc
for (int i = 1; i < nConvert; i++) {
float dx = intersliceDistance(dcmList[indx0],dcmList[dcmSort[i].indx]);
if ((!isSameFloat(dx,0.0f)) && (dx < prevDx)) {
//for (int j = 1; j < nConvert; j++)
// reportPos(dcmList[dcmSort[j].indx]);
printMessage("Slices skipped: image position not sequential, admonish your vendor (Siemens OOG?)\n");
return i;
}
Expand Down Expand Up @@ -3031,6 +3037,17 @@ float vec3maxMag (vec3 v) { //return signed vector with maximum magnitude
return mx;
}

vec3 makePositive(vec3 v) {
//we do not no order of cross product or order of instance number (e.g. head->foot, foot->head)
// this function matches the polarity of slice direction inferred from patient position and image orient
vec3 ret = v;
if (vec3maxMag(v) >= 0.0) return ret;
ret.v[0] = -ret.v[0];
ret.v[1] = -ret.v[1];
ret.v[2] = -ret.v[2];
return ret;
}

void vecRep (vec3 v) { //normalize vector length
printMessage("[%g %g %g]\n", v.v[0], v.v[1], v.v[2]);
}
Expand All @@ -3056,21 +3073,27 @@ float computeGantryTiltPrecise(struct TDICOMdata d1, struct TDICOMdata d2, int i
if (isSameFloat(len, 0.0)) return ret;
}
if (isnan(slice_vector.v[0])) return ret;
slice_vector = makePositive(slice_vector);
vec3 read_vector = setVec3(d1.orient[1],d1.orient[2],d1.orient[3]);
vec3 phase_vector = setVec3(d1.orient[4],d1.orient[5],d1.orient[6]);
vec3 slice_vector90 = crossProduct(read_vector ,phase_vector); //perpendicular
float len90 = vec3Length(slice_vector90);
slice_vector90 = makePositive(slice_vector90);
float len90 = vec3Length(slice_vector90);
if (isSameFloat(len90, 0.0)) return ret;
float dotX = dotProduct(slice_vector90, slice_vector);
float cosX = dotX / (len * len90);
float degX = acos(cosX) * (180.0 / M_PI); //arccos, radian -> degrees
if (!isSameFloat(cosX, 1.0))
ret = degX;
if ((isSameFloat(ret, 0.0)) && (isSameFloat(ret, d1.gantryTilt)) ) return ret;
if ((isSameFloat(ret, 0.0)) && (isSameFloat(ret, d1.gantryTilt)) ) return 0.0;
//determine if gantry tilt is positive or negative
vec3 signv = crossProduct(slice_vector,slice_vector90);
float sign = vec3maxMag(signv);
if (sign > 0.0) ret = -ret; //the length of len90 was negative, negative gantry tilt
float sign = vec3maxMag(signv);
if (isSameFloatGE(ret, 0.0)) return 0.0; //parallel vectors
if (sign > 0.0) ret = -ret; //the length of len90 was negative, negative gantry tilt
//while (ret >= 89.99) ret -= 90;
//while (ret <= -89.99) ret += 90;
if (isSameFloatGE(ret, 0.0)) return 0.0;
if ((isVerbose) || (isnan(ret))) {
printMessage("Gantry Tilt Parameters (see issue 253)\n");
printMessage(" Read ="); vecRep(read_vector);
Expand Down

0 comments on commit 8561c3e

Please sign in to comment.