Skip to content

Commit

Permalink
Detect echo number for Siemens XA that omit 0018,0086 (#568)
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Jan 21, 2022
1 parent 53281c4 commit 57a3e9d
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ The following tools exploit dcm2niix
- [Brain imAgiNg Analysis iN Arcana (Banana)](https://pypi.org/project/banana/) is a collection of brain imaging analysis workflows, it uses dcm2niix for format conversions.
- [BraTS-Preprocessor](https://neuronflow.github.io/BraTS-Preprocessor/) uses dcm2niix to import files for [Brain Tumor Segmentation](https://www.frontiersin.org/articles/10.3389/fnins.2020.00125/full).
- [clinica](https://github.com/aramis-lab/clinica) is a software platform for clinical neuroimaging studies that uses dcm2niix to convert DICOM images.
- [bidsconvertr](https://github.com/wulms/bidsconvertr) uses R to converts DICOM data to NIfTI and finally to BIDS.
- [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.
- [BioImage Suite Web Project](https://github.com/bioimagesuiteweb/bisweb) is a JavaScript project that uses dcm2niix for its DICOM conversion module.
Expand Down
20 changes: 20 additions & 0 deletions Siemens/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ While X-series consoles allow users to export data as enhanced, mosaic or classi
When creating enhanced DICOMs diffusion information is provided in public tags. Based on a limited sample, it seems that classic DICOMs do not store diffusion data for XA10, and use private tags for [XA11](https://www.nitrc.org/forum/forum.php?thread_id=10013&forum_id=4703).

Public Tags

```
(0018,9089) FD -0.20\-0.51\-0.83 #DiffusionGradientOrientation
(0018,9087) FD 1000 #DiffusionBValue
```

Private Tags

```
(0019,100c) IS 1000 #SiemensDiffusionBValue
(0019,100e) FD -0.20\-0.51\-0.83 #SiemensDiffusionGradientOrientation
Expand All @@ -30,6 +32,24 @@ Private Tags

In theory, the public DICOM tag 'Frame Acquisition Date Time' (0018,9074) and the private tag 'Time After Start' (0021,1104) should each allow one to infer slice timing. The tag 0018,9074 uses the DT (date time) format, for example "20190621095520.330000" providing the YYYYYMMDDHHMMSS. Unfortunately, the Siemens de-identification routines will scramble these values, as time of data could be considered an identifiable attribute. The tag 0021,1104 is saved in DS (decimal string) format, for example "4.635" reporting the number of seconds since acquisition started. Be aware that some [Siemens Vida multi-band sequences](https://github.com/rordenlab/dcm2niix/issues/303) appear to fill these tags with the single-band times rather than the actual acquisition times. Therefore, neither of these two methods is perfectly reliable in determining slice timing.

The private `ICE_Dims` (0021,1106) tag can prove useful for parsing data. The list below is specific to XA scans: [SPM12](https://github.com/spm/spm12/blob/3085dac00ac804adb190a7e82c6ef11866c8af02/spm_dicom_convert.m#L268) suggests that this tag used to contain fewer elements. dcm2niix will use 0021,1106 to deduce echo number for [XA20 sequences that do not generate the public Echo Number (0018,0086)](https://github.com/rordenlab/dcm2niix/issues/568) tag. For example, consider an image of the 4th echo and 160th slice:

```
(0021,1106) LO [X_4_1_1_1_1_160_1_1_1_1_1_277] # ICE_Dims
```

1. eco = echo number
2. phs = phase encode
3. set =
4. rep = repetition
5. seg = segment
6. par = partition
7. slc = slice
8. idA = optional index
9. idB = optional index
10. idC = optional index
11. avg = average number

## CSA Header

Many crucial Siemens parameters are stored in the [proprietary CSA header](http://nipy.org/nibabel/dicom/siemens_csa.html), in particular the CSA Image Header Info (0029, 1010) and CSA Series Header Info (0029, 1020). These have binary sections that allows quick reading for many useful parameters. They also include an ASCII text portion that includes a lot of information but is slow to parse and poorly curated. Be aware that Siemens Vida scanners do not generate a CSA header.
Expand Down
17 changes: 16 additions & 1 deletion console/nii_dicom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ void dcmStrDigitsDotOnlyKey(char key, char *lStr) {
} else if (!isKey)
lStr[i] = ' ';
}
} //dcmStrDigitsOnlyKey()
} //dcmStrDigitsDotOnlyKey()

void dcmStrDigitsOnlyKey(char key, char *lStr) {
//e.g. string "p2s3" returns 2 if key=="p" and 3 if key=="s"
Expand Down Expand Up @@ -4290,6 +4290,7 @@ const uint32_t kEffectiveTE = 0x0018 + (0x9082 << 16);
#define kSequenceVariant21 0x0021 + (0x105B << 16) //CS
#define kPATModeText 0x0021 + (0x1009 << 16) //LO, see kImaPATModeText
#define kTimeAfterStart 0x0021 + (0x1104 << 16) //DS
#define kICE_dims 0x0021 + (0x1106 << 16) //LO [X_4_1_1_1_1_160_1_1_1_1_1_277]
#define kPhaseEncodingDirectionPositiveSiemens 0x0021 + (0x111C << 16) //IS
//#define kRealDwellTime 0x0021+(0x1142<< 16 )//IS
#define kBandwidthPerPixelPhaseEncode21 0x0021 + (0x1153 << 16) //FD
Expand Down Expand Up @@ -5800,6 +5801,20 @@ const uint32_t kEffectiveTE = 0x0018 + (0x9082 << 16);
//printf("x\t%d\t%g\tkTimeAfterStart\n", acquisitionTimesGE_UIH, d.CSA.sliceTiming[acquisitionTimesGE_UIH]);
acquisitionTimesGE_UIH++;
break;
case kICE_dims: { //issue568: LO (0021,1106) [X_4_1_1_1_1_160_1_1_1_1_1_277]
if ((d.manufacturer != kMANUFACTURER_SIEMENS) || (d.echoNum > 1))
break;
char iceStr[kDICOMStr];
dcmStr(lLength, &buffer[lPos], iceStr);
dcmStrDigitsOnly(iceStr);
char *end;
int echo = (int)strtol(iceStr, &end, 10);
//printMessage("%d:%d:'%s'\n", d.echoNum, echo, iceStr);
if (iceStr != end)
d.echoNum = echo;
//printMessage("%d:'%s'\n", echo, iceStr);
break;
}
case kPhaseEncodingDirectionPositiveSiemens: {
if (d.manufacturer != kMANUFACTURER_SIEMENS)
break;
Expand Down

0 comments on commit 57a3e9d

Please sign in to comment.