Skip to content

Commit

Permalink
TablePosition (#726)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Jul 25, 2024
1 parent e039cb3 commit 446419e
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 5 deletions.
12 changes: 8 additions & 4 deletions BIDS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,9 @@ Data unique to [GE](https://github.com/rordenlab/dcm2niix/tree/master/GE). Deter
| ASLLabelingTechnique | | DICOM tag 0043,10A4 | D |
| LabelingDuration | s | DICOM tag 0043,10A5 | B |
| SliceTiming | s | [see notes](https://github.com/rordenlab/dcm2niix/tree/master/GE#slice-timing) | B |
| CompressedSensingFactor | | DICOM tag 0043,10b7 | D |
| DeepLearningFactor | | DICOM tag 0043,10ca | D |
| CompressedSensingFactor | | DICOM tag 0043,10B7 | D |
| TablePosition | mm | DICOM tag 0043,10B2 | B |
| DeepLearningFactor | | DICOM tag 0043,10CA | D |

### Manufacturer Philips

Expand All @@ -258,11 +259,12 @@ Data unique to Philips, including [custom intensity scaling](https://www.ncbi.nl
| PhilipsRWVIntercept | | DICOM tag 0040,9224 | D |
| PhilipsRescaleSlope | | DICOM tag 0028,1053 | D |
| PhilipsRescaleIntercept | | DICOM tag 0028,1052 | D |
| PhilipsScaleSlope | | DICOM tag 2005,100E | D |
| UsePhilipsFloatNotDisplayScaling | | dcm2niix option `-p y` or `-p n` | D |
| PartialFourierEnabled | | DICOM tag 0018,9081, `YES` | D |
| PhaseEncodingStepsNoPartialFourier | | DICOM tag 0018,9231 | D |
| WaterFatShift | | DICOM tag 2001,1022 | D |
| PhilipsScaleSlope | | DICOM tag 2005,100E | D |
| TablePosition | mm | DICOM tag 2005,143D | B |

### Manufacturer Siemens (Arterial Spin Labeling)

Expand Down Expand Up @@ -332,6 +334,7 @@ Fields specific to Siemens V*-series (e.g. VB, VE) MRI systems (e.g. Verio, Trio
| ConsistencyInfo | | The more complete software version, e.g. VE11C or VE11E instead of just VE11. | D |
| CoilCombinationMethod | | Detects `Sum of Squares` and `Adaptive Combine` | B |
| MatrixCoilMode | | Detects `SENSE` and `GRAPPA` | B |
| TablePosition | mm | DICOM tag 0019,1014 | B |
| DwellTime | | DICOM tag 0019,1018 | B |
| BandwidthPerPixelPhaseEncode | Hz | DICOM tag 0019,1028 | D |
| ImageOrientationText | | DICOM tag 0051,100E | D |
Expand All @@ -347,9 +350,10 @@ Fields specific to [Siemens XA-series](https://github.com/rordenlab/dcm2niix/tre
| BandwidthPerPixelPhaseEncode | Hz | DICOM tag 0021,1153 | D |
| ScanningSequence | | DICOM tag 0021,105a | D |
| PostLabelingDelay | s | DICOM tag 0018,9258 | B |
| TablePosition | mm | DICOM tag 0021,1005 | B |
| NonlinearGradientCorrection | b | 0008,0008 or 0021,1175 | B |
| PhaseEncodingDirection | | polarity from 0021,111c | B |
| SpoilingState | | 0021,105B | B |
| SpoilingState | | DICOM tag 0021,105B | B |

Siemens also includes some sequence information in the private MRPhoenixProtocol (0021,1019) tag. You can view this with [gdcmdump](https://gdcm.sourceforge.net/html/gdcmdump.html), e.g. `gdcmdump --mrprotocol img.dcm`. Fields that dcm2niix inspects include `sPat.lAccelFact3D `, `sPat.lAccelFactPE`, `sPat.lRefLinesPE` and `sPat.ucPATMode`. The behavior of dcm2niix will be more well documented as our understanding of this tag improves.

Expand Down
27 changes: 27 additions & 0 deletions console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,10 @@ struct TDICOMdata clear_dicom_data() {
strcpy(d.patientAge, "");
d.CSA.bandwidthPerPixelPhaseEncode = 0.0;
d.CSA.mosaicSlices = 0;
d.CSA.tablePos[0] = -1.0; //unset
d.CSA.tablePos[1] = 0.0; // x
d.CSA.tablePos[2] = 0.0; // y
d.CSA.tablePos[3] = 0.0; // z
d.CSA.sliceNormV[1] = 0.0;
d.CSA.sliceNormV[2] = 0.0;
d.CSA.sliceNormV[3] = 1.0; //default Siemens Image Numbering is F>>H https://www.mccauslandcenter.sc.edu/crnl/tools/stc
Expand Down Expand Up @@ -4472,6 +4476,7 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
// https://nciphub.org/groups/qindicom/wiki/DiffusionrelatedDICOMtags:experienceacrosssites?action=pdf
#define kDiffusion_bValueSiemens 0x0019 + (0x100C << 16) //IS
#define kDiffusionGradientDirectionSiemens 0x0019 + (0x100E << 16) //FD
#define kImaRelTablePosition 0x0019 + (0x1014 << 16) //IS[]
#define kSeriesPlaneGE 0x0019 + (0x1017 << 16) //SS
#define kDwellTime 0x0019 + (0x1018 << 16) //IS in NSec, see https://github.com/rordenlab/dcm2niix/issues/127
#define kLastScanLoc 0x0019 + (0x101B << 16)
Expand Down Expand Up @@ -4513,6 +4518,7 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
#define kTemporalPositionIndex 0x0020 + uint32_t(0x9128 << 16) // UL
#define kDimensionIndexPointer 0x0020 + uint32_t(0x9165 << 16)
//Private Group 21 as Used by Siemens:
#define kRelTablePosition 0x0021 + (0x1005 << 16) //IS
#define kScanningSequenceSiemens 0x0021 + (0x105A << 16) //CS n.b. for GE this is Diffusion direction of SL!
#define kSequenceVariant21 0x0021 + (0x105B << 16) //CS Siemens ONLY: For GE this is TaggingFlipAngle
#define kScanOptionsSiemens 0x0021 + (0x105C << 16) //CS Siemens ONLY
Expand Down Expand Up @@ -4643,6 +4649,7 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
#define kDiffusionDirectionFH 0x2005 + (0x10B2 << 16)
#define kDeepLearningPhilips 0x2005 + (0x1110 << 16)
#define kPrivatePerFrameSq 0x2005 + (0x140F << 16)
#define kMRStackTablePosLong 0x2005 + (0x143C << 16) //FL
#define kMRImageDiffBValueNumber 0x2005 + (0x1412 << 16) //IS
#define kMRImageGradientOrientationNumber 0x2005+(0x1413 << 16) //IS
#define kMRImageLabelType 0x2005 + (0x1429 << 16) //CS ASL LBL_CTL https://github.com/physimals/dcm_convert_phillips/
Expand Down Expand Up @@ -5950,6 +5957,13 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
d.CSA.dtiV[3] = v[2];
break;
}
case kImaRelTablePosition: {
if (d.manufacturer != kMANUFACTURER_SIEMENS)
break;
dcmMultiFloat(lLength, (char *)&buffer[lPos], 3, &d.CSA.tablePos[0]); //slice position
d.CSA.tablePos[0] = 1.0; //set
break;
}
case kNumberOfDiffusionT2GE: {
if (d.manufacturer != kMANUFACTURER_GE)
break;
Expand Down Expand Up @@ -6755,6 +6769,13 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
d.isEPI = true;
break; //warp
}
case kRelTablePosition: {
if (d.manufacturer != kMANUFACTURER_SIEMENS)
break;
dcmMultiFloat(lLength, (char *)&buffer[lPos], 3, &d.CSA.tablePos[0]); //slice position
d.CSA.tablePos[0] = 1.0; //set
break;
}
case kScanningSequenceSiemens:
if (d.manufacturer == kMANUFACTURER_SIEMENS)
dcmStr(lLength, &buffer[lPos], scanningSequenceSiemens);
Expand Down Expand Up @@ -7093,6 +7114,12 @@ const uint32_t kEffectiveTE = 0x0018 + uint32_t(0x9082 << 16); //FD
if (toupper(buffer[lPos]) == 'L') d.aslFlags = kASL_FLAG_PHILIPS_LABEL;
if (toupper(buffer[lPos]) == 'C') d.aslFlags = kASL_FLAG_PHILIPS_CONTROL;
break;
case kMRStackTablePosLong: //FL
if (d.manufacturer != kMANUFACTURER_PHILIPS)
break;
d.CSA.tablePos[3] = dcmFloat(lLength, &buffer[lPos], d.isLittleEndian);
d.CSA.tablePos[0] = 1.0;
break;
case kMRImageDiffBValueNumber:
if (d.manufacturer != kMANUFACTURER_PHILIPS)
break;
Expand Down
2 changes: 1 addition & 1 deletion console/nii_dicom.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
} TCSAitem; //Siemens csa item structure
#endif
struct TCSAdata {
float sliceTiming[kMaxEPI3D], dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
float sliceTiming[kMaxEPI3D], dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration, tablePos[4];
int coilNumber, numDti, SeriesHeader_offset, SeriesHeader_length, multiBandFactor, sliceOrder, slice_start, slice_end, mosaicSlices, protocolSliceNumber1, phaseEncodingDirectionPositive;
bool isPhaseMap;
char bidsDataType[kDICOMStr]; //anat, func, dwi
Expand Down
4 changes: 4 additions & 0 deletions console/nii_dicom_batch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,11 @@ tse3d: T2*/
json_Float(fp, "\t\"SpacingBetweenSlices\": %g,\n", d.zSpacing);
}
//if (!opts.isAnonymizeBIDS) //issue668 is SAR identifiable??
//an identical sequence can create different SAR and TablePosition depending on participant
json_Float(fp, "\t\"SAR\": %g,\n", d.SAR);
if (d.CSA.tablePos[0] > 0.0)
fprintf(fp, "\t\"TablePosition\": [\n\t\t%g,\n\t\t%g,\n\t\t%g\t],\n", d.CSA.tablePos[1], d.CSA.tablePos[2], d.CSA.tablePos[3]);

if (d.numberOfAverages > 1.0)
json_Float(fp, "\t\"NumberOfAverages\": %g,\n", d.numberOfAverages);
if ((d.echoNum > 1) || ((d.isMultiEcho) && (d.echoNum > 0)))
Expand Down

0 comments on commit 446419e

Please sign in to comment.