[med-svn] [dcm2niix] 01/04: New upstream version 1.0.20170624
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Thu Jul 13 18:14:18 UTC 2017
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/master
in repository dcm2niix.
commit 32a51618658343319bcb9c056b1a6bec13c6d12b
Author: Ghislain Antony Vaillant <ghisvail at gmail.com>
Date: Thu Jul 13 18:59:50 2017 +0100
New upstream version 1.0.20170624
---
.gitmodules | 3 +
.travis.yml | 5 ++
COMPILE.md | 26 +++---
README.md | 18 +++-
SuperBuild/External-OPENJPEG.cmake | 6 +-
SuperBuild/External-YAML-CPP.cmake | 6 +-
SuperBuild/SuperBuild.cmake | 22 +++--
console/CMakeLists.txt | 9 ++
console/main_console.cpp | 5 +-
console/nii_dicom.cpp | 176 +++++++++++++++++++++++++------------
console/nii_dicom.h | 14 +--
console/nii_dicom_batch.cpp | 85 +++++++++++++-----
console/nii_foreign.cpp | 1 -
13 files changed, 252 insertions(+), 124 deletions(-)
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..511dc74
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "dcm_qa"]
+ path = dcm_qa
+ url = http://github.com/neurolabusc/dcm_qa
diff --git a/.travis.yml b/.travis.yml
index 79f8259..80f4058 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,13 @@ matrix:
- os: osx
env: TARGET=mac
+before_install:
+ - git submodule update --init --depth=3 dcm_qa
+
script:
- mkdir build && cd build && cmake -DBATCH_VERSION=ON -DUSE_OPENJPEG=ON .. && make && cd -
+ - export PATH=$PWD/build/bin:$PATH
+ - cd dcm_qa; ./batch.sh
before_deploy:
- export DATE=`date +%-d-%b-%Y`
diff --git a/COMPILE.md b/COMPILE.md
index ed69b48..46ce378 100644
--- a/COMPILE.md
+++ b/COMPILE.md
@@ -12,7 +12,7 @@ The text below generally describes how to build dcm2niix using the [GCC](https:/
You can also build the software without C-make. The easiest way to do this is to run the function "make" from the "console" folder. Note that this only creates the default version of dcm2niix, not the optional batch version described above. The make command simply calls the g++ compiler, and if you want you can tune this for your build. In essence, the make function simply calls
```
-g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper
+g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper
```
The following sub-sections list how you can modify this basic recipe for your needs.
@@ -21,7 +21,7 @@ The following sub-sections list how you can modify this basic recipe for your ne
If we have zlib, we can use it (-lz) and disable [miniz](https://code.google.com/p/miniz/) (-myDisableMiniZ)
```
-g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix -lz -DmyDisableMiniZ
+g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -dead_strip -o dcm2niix -lz -DmyDisableMiniZ
```
##### MINGW BUILD
@@ -29,7 +29,7 @@ g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cp
If you use the (obsolete) compiler MinGW on Windows you will want to include the rare libgcc libraries with your executable so others can use it. Here I also demonstrate the optional "-DmyDisableZLib" to remove zip support.
```
-g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -static-libgcc
+g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -static-libgcc
```
##### DISABLING CLASSIC JPEG
@@ -37,7 +37,7 @@ g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cp
DICOM images can be stored as either raw data or compressed using one of many formats as described by the [transfer syntaxes](https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage#Transfer_Syntaxes_and_Compressed_Images). One of the compressed formats is the lossy classic JPEG format (which is separate from and predates the lossy JPEG 2000 format). This software comes with the [NanoJPEG](http://keyj.emphy.de/nanojpeg/) library to handle these images. However, you can use the `my [...]
```
-g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp -o dcm2niix -DmyDisableClassicJPEG -DmyDisableOpenJPEG -DmyDisableJasper
+g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -o dcm2niix -DmyDisableClassicJPEG -DmyDisableOpenJPEG -DmyDisableJasper
```
##### USING LIBJPEG-TURBO TO DECODE CLASSIC JPEG
@@ -45,7 +45,7 @@ g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp nifti1_io_co
By default, classic JPEG images will be decoded using the [compact NanoJPEG decoder](http://keyj.emphy.de/nanojpeg/). However, the compiler directive `myTurboJPEG` will create an executable based on the [libjpeg-turbo](http://www.libjpeg-turbo.org) library. This library is a faster decoder and is the standard for many Linux distributions. On the other hand, the lossy classic JPEG is rarely used for DICOM images, so this compilation has extra dependencies and can result in a larger execu [...]
```
-g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper -DmyTurboJPEG -I/opt/libjpeg-turbo/include /opt/libjpeg-turbo/lib/libturbojpeg.a
+g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper -DmyTurboJPEG -I/opt/libjpeg-turbo/include /opt/libjpeg-turbo/lib/libturbojpeg.a
```
##### JPEG2000 BUILD
@@ -59,23 +59,23 @@ g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp ni
You should then be able to run then run:
```
-g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -lopenjp2
+g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -lopenjp2
```
But in my experience this works best if you explicitly tell the software how to find the libraries, so your compile will probably look like one of these two options:
```
-g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -I/usr/local/include /usr/local/lib/libopenjp2.a
+g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -I/usr/local/include/openjpeg-2.1 /usr/local/lib/libopenjp2.a
```
```
-g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -I/usr/local/lib /usr/local/lib/libopenjp2.a
+g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -I/usr/local/lib /usr/local/lib/libopenjp2.a
```
If you want to build this with JPEG2000 decompression support using Jasper: You will need to have the Jasper (http://www.ece.uvic.ca/~frodo/jasper/) and libjpeg (http://www.ijg.org) libraries installed which for Linux users may be as easy as running 'sudo apt-get install libjasper-dev' (otherwise, see http://www.ece.uvic.ca/~frodo/jasper/#doc). You can then run:
```
-g++ -O3 -DmyDisableOpenJPEG -DmyEnableJasper -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -s -o dcm2niix -ljasper -ljpeg
+g++ -O3 -DmyDisableOpenJPEG -DmyEnableJasper -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -s -o dcm2niix -ljasper -ljpeg
```
##### VISUAL STUDIO BUILD
@@ -84,7 +84,7 @@ This software can be compiled with VisualStudio 2015. This example assumes the c
```
vcvarsall amd64
-cl /EHsc main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp -DmyDisableOpenJPEG -DmyDisableJasper /odcm2niix
+cl /EHsc main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -DmyDisableOpenJPEG -DmyDisableJasper /odcm2niix
```
##### OSX BUILD WITH BOTH 32 AND 64-BIT SUPPORT
@@ -93,11 +93,11 @@ Building command line version universal binary from OSX 64 bit system:
This requires a C compiler. With a terminal, change directory to the 'conosle' folder and run the following:
```
-g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -arch i386 -o dcm2niix32
+g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -dead_strip -arch i386 -o dcm2niix32
```
```
-g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix64
+g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -dead_strip -o dcm2niix64
```
```
@@ -140,4 +140,4 @@ CXXFLAGS = -DmyUseCOut -DWX_PRECOMP ....
i.) For a full refresh
rm clipboard
rm *.o
-make
+make
\ No newline at end of file
diff --git a/README.md b/README.md
index 075ff2f..43bf91f 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,16 @@ This software is open source. The bulk of the code is covered by the BSD license
## Versions
+23-June-2017
+ - [Ensure slice timing always encoded for Siemens EPI](https://github.com/neurolabusc/dcm_qa/issues/4#issuecomment-310707906)
+ - [Integrates validation](https://github.com/neurolabusc/dcm_qa)
+ - JSON fix (InstitutionName -> InstitutionAddress)
+
+21-June-2017
+ - Read DICOM header in 1Mb segments rather than loading whole file : reduces ram usage and [faster for systems with slow io](https://github.com/rordenlab/dcm2niix/issues/104).
+ - Report [TotalReadoutTime](https://github.com/rordenlab/dcm2niix/issues/98).
+ - Fix JPEG2000 support in [Superbuild](https://github.com/rordenlab/dcm2niix/issues/105).
+
28-May-2017
- Remove all derived images from [Philips DTI series](http://www.nitrc.org/forum/message.php?msg_id=21025).
- Provide some [Siemens EPI sequence details](https://github.com/rordenlab/dcm2niix/issues).
@@ -152,7 +162,13 @@ make
**optional building with OpenJPEG:**
-Support for JPEG2000 using OpenJPEG is optional. To build with OpenJPEG change the cmake command to `cmake -DUSE_OPENJPEG=ON ..`
+Support for JPEG2000 using OpenJPEG is optional. To build with OpenJPEG change the cmake command to `cmake -DUSE_OPENJPEG=ON ..`:
+
+```bash
+mkdir build && cd build
+cmake -DUSE_OPENJPEG=ON ..
+make
+```
**optional batch processing version:**
diff --git a/SuperBuild/External-OPENJPEG.cmake b/SuperBuild/External-OPENJPEG.cmake
index 38f7301..5cfdb51 100644
--- a/SuperBuild/External-OPENJPEG.cmake
+++ b/SuperBuild/External-OPENJPEG.cmake
@@ -1,4 +1,4 @@
-set(OPENJPEG_TAG 151e322) # version openjepg-2.1
+set(OPENJPEG_TAG v2.1-static) # version v2.1-static
ExternalProject_Add(openjpeg
GIT_REPOSITORY "${git_protocol}://github.com/ningfei/openjpeg.git"
@@ -9,7 +9,7 @@ ExternalProject_Add(openjpeg
-Wno-dev
--no-warn-unused-cli
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
- -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
+ -DCMAKE_INSTALL_PREFIX=${DEP_INSTALL_DIR}
)
-set(OPENJPEG_DIR ${CMAKE_BINARY_DIR}/lib/openjpeg-2.1)
+set(OPENJPEG_DIR ${DEP_INSTALL_DIR}/lib/openjpeg-2.1)
diff --git a/SuperBuild/External-YAML-CPP.cmake b/SuperBuild/External-YAML-CPP.cmake
index ada7d8f..305faaf 100644
--- a/SuperBuild/External-YAML-CPP.cmake
+++ b/SuperBuild/External-YAML-CPP.cmake
@@ -1,4 +1,4 @@
-set(YAML-CPP_TAG 5c3cb09) # version yaml-cpp-0.5.3
+set(YAML-CPP_TAG yaml-cpp-0.5.3) # version yaml-cpp-0.5.3
ExternalProject_Add(yaml-cpp
GIT_REPOSITORY "${git_protocol}://github.com/ningfei/yaml-cpp.git"
@@ -9,7 +9,7 @@ ExternalProject_Add(yaml-cpp
-Wno-dev
--no-warn-unused-cli
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
- -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
+ -DCMAKE_INSTALL_PREFIX=${DEP_INSTALL_DIR}
)
-set(YAML-CPP_DIR ${CMAKE_BINARY_DIR}/lib/cmake/yaml-cpp)
+set(YAML-CPP_DIR ${DEP_INSTALL_DIR}/lib/cmake/yaml-cpp)
diff --git a/SuperBuild/SuperBuild.cmake b/SuperBuild/SuperBuild.cmake
index 969b95a..4c37373 100644
--- a/SuperBuild/SuperBuild.cmake
+++ b/SuperBuild/SuperBuild.cmake
@@ -15,6 +15,7 @@ endif()
# Basic CMake build settings
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release;RelWithDebInfo;MinSizeRel")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
option(USE_STATIC_RUNTIME "Use static runtime" ON)
@@ -30,6 +31,14 @@ include(ExternalProject)
set(DEPENDENCIES)
+option(INSTALL_DEPENDENCIES "Optionally install built dependent libraries (OpenJPEG and yaml-cpp) for future use." OFF)
+
+if(INSTALL_DEPENDENCIES)
+ set(DEP_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+else()
+ set(DEP_INSTALL_DIR ${CMAKE_BINARY_DIR})
+endif()
+
if(USE_OPENJPEG)
message("-- Build with OpenJPEG: ${USE_OPENJPEG}")
@@ -77,6 +86,7 @@ ExternalProject_Add(console
-Wno-dev
--no-warn-unused-cli
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
-DUSE_STATIC_RUNTIME:BOOL=${USE_STATIC_RUNTIME}
-DUSE_SYSTEM_ZLIB:BOOL=${USE_SYSTEM_ZLIB}
-DUSE_SYSTEM_TURBOJPEG:BOOL=${USE_SYSTEM_TURBOJPEG}
@@ -87,23 +97,11 @@ ExternalProject_Add(console
# yaml-cpp
-DBATCH_VERSION:BOOL=${BATCH_VERSION}
-DYAML-CPP_DIR:PATH=${YAML-CPP_DIR}
- -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
)
install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/ DESTINATION bin
USE_SOURCE_PERMISSIONS)
-# Install dependent libraries for future use
-if(BUILD_OPENJPEG OR BUILD_YAML-CPP)
- option(INSTALL_DEPENDENCIES "Optionally install dependent libraries (OpenJPEG and yaml-cpp) for future use." OFF)
- if(INSTALL_DEPENDENCIES)
- install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include
- USE_SOURCE_PERMISSIONS)
- install(DIRECTORY ${CMAKE_BINARY_DIR}/lib/ DESTINATION lib
- USE_SOURCE_PERMISSIONS)
- endif()
-endif()
-
option(BUILD_DOCS "Build documentation (manpages)" OFF)
if(BUILD_DOCS)
add_subdirectory(docs)
diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt
index 8e98cdc..54d9749 100644
--- a/console/CMakeLists.txt
+++ b/console/CMakeLists.txt
@@ -80,6 +80,15 @@ if(USE_OPENJPEG)
option(OpenJPEG_DIR "Path to OpenJPEG configuration file" "")
find_package(OpenJPEG)
+
+ if(WIN32)
+ if(BUILD_SHARED_LIBS)
+ add_definitions(-DOPJ_EXPORTS)
+ else()
+ add_definitions(-DOPJ_STATIC)
+ endif()
+ endif()
+
target_include_directories(dcm2niix PRIVATE ${OPENJPEG_INCLUDE_DIRS})
target_link_libraries(dcm2niix ${OPENJPEG_LIBRARIES})
else ()
diff --git a/console/main_console.cpp b/console/main_console.cpp
index 6434aa1..fa65b95 100644
--- a/console/main_console.cpp
+++ b/console/main_console.cpp
@@ -78,10 +78,11 @@ void showHelp(const char * argv[], struct TDCMopts opts) {
if (opts.isAnonymizeBIDS) bidsCh = 'y'; else bidsCh = 'n';
printf(" -ba : anonymize BIDS (y/n, default %c)\n", bidsCh);
#ifdef mySegmentByAcq
- printf(" -f : filename (%%a=antenna (coil) number, %%c=comments, %%d=description, %%e echo number, %%f=folder name, %%i ID of patient, %%j seriesInstanceUID, %%k studyInstanceUID, %%m=manufacturer, %%n=name of patient, %%p=protocol, %%q=sequence number, %%s=series number, %%t=time, %%u=acquisition number, %%z sequence name; default '%s')\n",opts.filename);
+ #define kQstr " %%q=sequence number,"
#else
- printf(" -f : filename (%%a=antenna (coil) number, %%c=comments, %%d=description, %%e echo number, %%f=folder name, %%i ID of patient, %%j seriesInstanceUID, %%k studyInstanceUID, %%m=manufacturer, %%n=name of patient, %%p=protocol, %%s=series number, %%t=time, %%u=acquisition number, %%z sequence name; default '%s')\n",opts.filename);
+ #define kQstr ""
#endif
+ printf(" -f : filename (%%a=antenna (coil) number, %%c=comments, %%d=description, %%e echo number, %%f=folder name, %%i ID of patient, %%j seriesInstanceUID, %%k studyInstanceUID, %%m=manufacturer, %%n=name of patient, %%p=protocol,%s %%s=series number, %%t=time, %%u=acquisition number, %%x study ID; %%z sequence name; default '%s')\n", kQstr, opts.filename);
printf(" -h : show help\n");
printf(" -i : ignore derived, localizer and 2D images (y/n, default n)\n");
printf(" -t : text notes includes private patient details (y/n, default n)\n");
diff --git a/console/nii_dicom.cpp b/console/nii_dicom.cpp
index 667426a..624bf4d 100644
--- a/console/nii_dicom.cpp
+++ b/console/nii_dicom.cpp
@@ -50,7 +50,7 @@
#include <jasper/jasper.h>
#endif
#ifndef myDisableOpenJPEG
- #include <openjpeg.h>
+ #include "openjpeg.h"
#ifdef myEnableJasper
ERROR: YOU CAN NOT COMPILE WITH myEnableJasper AND NOT myDisableOpenJPEG OPTIONS SET SIMULTANEOUSLY
@@ -621,6 +621,7 @@ struct TDICOMdata clear_dicom_data() {
d.angulation[i] = 0.0f;
d.xyzMM[i] = 1;
}
+ d.CSA.sliceTiming[0] = -1.0f; //impossible value denotes not known
d.CSA.numDti = 0;
for (int i=0; i < 5; i++)
d.xyzDim[i] = 1;
@@ -637,15 +638,18 @@ struct TDICOMdata clear_dicom_data() {
strcpy(d.sequenceName, "");
strcpy(d.scanningSequence, "");
strcpy(d.sequenceVariant, "");
- strcpy(d.manufacturersModelName, "N/A");
+ strcpy(d.manufacturersModelName, "");
strcpy(d.procedureStepDescription, "");
strcpy(d.institutionName, "");
+ strcpy(d.referringPhysicianName, "");
strcpy(d.institutionAddress, "");
strcpy(d.deviceSerialNumber, "");
strcpy(d.softwareVersions, "");
strcpy(d.seriesInstanceUID, "");
+ strcpy(d.studyID, "");
strcpy(d.studyInstanceUID, "");
strcpy(d.bodyPartExamined,"");
+ d.phaseEncodingLines = 0;
d.patientPositionSequentialRepeats = 0;
d.isHasPhase = false;
d.isHasMagnitude = false;
@@ -660,11 +664,14 @@ struct TDICOMdata clear_dicom_data() {
d.TE = 0.0;
d.TI = 0.0;
d.flipAngle = 0.0;
+ d.bandwidthPerPixelPhaseEncode = 0.0;
d.fieldStrength = 0.0;
d.numberOfDynamicScans = 0;
d.echoNum = 1;
d.echoTrainLength = 0;
+ d.phaseEncodingSteps = 0;
d.coilNum = 1;
+ d.accelFactPE = 0.0;
d.patientPositionNumPhilips = 0;
d.imageBytes = 0;
d.intenScale = 1;
@@ -722,7 +729,6 @@ void dcmStrDigitsOnly(char* lStr) {
for (int i = 0; i < (int) len; i++)
if (!isdigit(lStr[i]) )
lStr[i] = ' ';
-
}
void dcmStr(int lLength, unsigned char lBuffer[], char* lOut) {
@@ -964,11 +970,9 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
for (int lT = 1; lT <= lnTag; lT++) {
memcpy(&tagCSA, &buff[lPos], sizeof(tagCSA)); //read tag
lPos +=sizeof(tagCSA);
-
// Storage order is always little-endian, so byte-swap required values if necessary
if (!littleEndianPlatform())
nifti_swap_4bytes(1, &tagCSA.nitems);
-
if (isVerbose > 1) //extreme verbosity: show every CSA tag
printMessage("%d CSA of %s %d\n",lPos, tagCSA.name, tagCSA.nitems);
if (tagCSA.nitems > 0) {
@@ -1001,19 +1005,16 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
else if (strcmp(tagCSA.name, "BandwidthPerPixelPhaseEncode") == 0)
CSA->bandwidthPerPixelPhaseEncode = csaMultiFloat (&buff[lPos], 3,lFloats, &itemsOK);
else if ((strcmp(tagCSA.name, "MosaicRefAcqTimes") == 0) && (tagCSA.nitems > 3) ){
-//#ifdef _MSC_VER
float * sliceTimes = (float *)malloc(sizeof(float) * (tagCSA.nitems + 1));
-//#else
-// float sliceTimes[tagCSA.nitems + 1];
-//#endif
csaMultiFloat (&buff[lPos], tagCSA.nitems,sliceTimes, &itemsOK);
float maxTimeValue, minTimeValue, timeValue1;
- for (int z = 0; z < kMaxDTI4D; z++)
- dti4D->S[z].sliceTiming = -1.0;
-
- if (itemsOK <= kMaxDTI4D)
+ for (int z = 0; z < kMaxEPI3D; z++)
+ CSA->sliceTiming[z] = -1.0;
+ if (itemsOK <= kMaxEPI3D) {
for (int z = 1; z <= itemsOK; z++)
- dti4D->S[z-1].sliceTiming = sliceTimes[z];
+ CSA->sliceTiming[z-1] = sliceTimes[z];
+ } else
+ printError("Please increase kMaxEPI3D and recompile\n");
CSA->multiBandFactor = 1;
timeValue1 = sliceTimes[1];
int nTimeZero = 0;
@@ -1090,6 +1091,15 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
return EXIT_SUCCESS;
} // readCSAImageHeader()
+void dcmMultiShorts (int lByteLength, unsigned char lBuffer[], int lnShorts, uint16_t *lShorts, bool littleEndian) {
+//read array of unsigned shorts US http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html
+ if ((lnShorts < 1) || (lByteLength != (lnShorts * 2))) return;
+ memcpy(&lShorts[0], (uint16_t *)&lBuffer[0], lByteLength);
+ bool swap = (littleEndian != littleEndianPlatform());
+ if (swap)
+ nifti_swap_2bytes(lnShorts, &lShorts[0]);
+} //dcmMultiShorts()
+
void dcmMultiFloat (int lByteLength, char lBuffer[], int lnFloats, float *lFloats) {
//warning: lFloats indexed from 1! will fill lFloats[1]..[nFloats]
if ((lnFloats < 1) || (lByteLength < 1)) return;
@@ -1316,10 +1326,8 @@ struct TDICOMdata nii_readParRec (char * parname, int isVerbose, struct TDTI4D
char *p = fgets (buff, LINESZ, fp);
bool isIntenScaleVaries = false;
bool isIndexSequential = true;
- for (int i = 0; i < kMaxDTI4D; i++) {
+ for (int i = 0; i < kMaxDTI4D; i++)
dti4D->S[i].V[0] = -1.0;
- dti4D->S[i].sliceTiming = -1.0;
- }
//d.dti4D = (TDTI *)malloc(kMaxDTI4D * sizeof(TDTI));
while (p) {
if (strlen(buff) < 1)
@@ -2455,14 +2463,12 @@ int isDICOMfile(const char * fname) { //0=NotDICOM, 1=DICOM, 2=Maybe(not Part 10
} //isDICOMfile()
struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, struct TDTI4D *dti4D) {
-//struct TDICOMdata readDICOMv(char * fname, bool isVerbose, int compressFlag) {
struct TDICOMdata d = clear_dicom_data();
strcpy(d.protocolName, ""); //erase dummy with empty
strcpy(d.protocolName, ""); //erase dummy with empty
strcpy(d.seriesDescription, ""); //erase dummy with empty
strcpy(d.sequenceName, ""); //erase dummy with empty
//do not read folders - code specific to GCC (LLVM/Clang seems to recognize a small file size)
-
struct stat s;
if( stat(fname,&s) == 0 ) {
if( !(s.st_mode & S_IFREG) ){
@@ -2489,31 +2495,42 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
printMessage( "File too small to be a DICOM image %s\n", fname);
return d;
}
+ //Since size of DICOM header is unknown, we will load it in 1mb segments
+ //This uses less RAM and makes is faster for computers with slow disk access
+ //Benefit is largest for 4D images.
+ //To disable caching and load entire file to RAM, compile with "-dmyLoadWholeFileToReadHeader"
+ //To implement the segments, we define these variables:
+ // fileLen = size of file in bytes
+ // MaxBufferSz = maximum size of buffer in bytes
+ // Buffer = array with n elements, where n is smaller of fileLen or MaxBufferSz
+ // lPos = position in Buffer (indexed from 0), 0..(n-1)
+ // lFileOffset = offset of Buffer in file: true file position is lOffset+lPos (initially 0)
+ #ifdef myLoadWholeFileToReadHeader
+ size_t MaxBufferSz = fileLen;
+ #else
+ size_t MaxBufferSz = 1000000; //ideally size of DICOM header, but this varies from 2D to 4D files
+ #endif
+ if (MaxBufferSz > fileLen)
+ MaxBufferSz = fileLen;
+ long lFileOffset = 0;
fseek(file, 0, SEEK_SET);
//Allocate memory
- unsigned char *buffer=(unsigned char *)malloc(fileLen+1);
+ unsigned char *buffer=(unsigned char *)malloc(MaxBufferSz+1);
if (!buffer) {
printError( "Memory exhausted!");
fclose(file);
return d;
}
//Read file contents into buffer
- size_t sz = fread(buffer, 1, fileLen, file);
- fclose(file);
- if (sz < fileLen) {
- printError("Only loaded %zu of %ld bytes for %s\n", sz, fileLen, fname);
+ size_t sz = fread(buffer, 1, MaxBufferSz, file);
+ if (sz < MaxBufferSz) {
+ printError("Only loaded %zu of %zu bytes for %s\n", sz, MaxBufferSz, fname);
+ fclose(file);
return d;
}
- //bool isPart10prefix = true; //assume 132 byte header http://nipy.bic.berkeley.edu/nightly/nibabel/doc/dicom/dicom_intro.html
- //if ((buffer[128] != 'D') || (buffer[129] != 'I') || (buffer[130] != 'C') || (buffer[131] != 'M')) {
- // if ((buffer[0] != 8) || (buffer[1] != 0) || (buffer[2] != 5) || (buffer[3] != 0)){
- // free (buffer);
- // return d;
- // }
- // isPart10prefix = false; //no 132 byte header, not a valid part 10 file http://fileformats.archiveteam.org/wiki/DICOM
- // d.isExplicitVR = false;
- // //printWarning("Not a valid part 10 DICOM (missing 'DICM' signature): %s\n", fname);
- //}
+ #ifdef myLoadWholeFileToReadHeader
+ fclose(file);
+ #endif
//DEFINE DICOM TAGS
#define kUnused 0x0001+(0x0001 << 16 )
#define kStart 0x0002+(0x0000 << 16 )
@@ -2528,6 +2545,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
#define kManufacturer 0x0008+(0x0070 << 16 )
#define kInstitutionName 0x0008+(0x0080 << 16 )
#define kInstitutionAddress 0x0008+(0x0081 << 16 )
+#define kReferringPhysicianName 0x0008+(0x0090 << 16 )
#define kSeriesDescription 0x0008+(0x103E << 16 ) // '0008' '103E' 'LO' 'SeriesDescription'
#define kManufacturersModelName 0x0008+(0x1090 << 16 )
#define kDerivationDescription 0x0008+(0x2111 << 16 )
@@ -2556,6 +2574,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
#define kRadionuclidePositronFraction 0x0018+(0x1076<< 16 )
#define kGantryTilt 0x0018+(0x1120 << 16 )
#define kXRayExposure 0x0018+(0x1152 << 16 )
+#define kAcquisitionMatrix 0x0018+(0x1310 << 16 ) //US
#define kFlipAngle 0x0018+(0x1314 << 16 )
#define kInPlanePhaseEncodingDirection 0x0018+(0x1312<< 16 ) //CS
#define kPatientOrient 0x0018+(0x5100<< 16 ) //0018,5100. patient orientation - 'HFS'
@@ -2564,12 +2583,14 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
#define kDiffusionDirectionGEX 0x0019+(0x10BB<< 16 ) //DS
#define kDiffusionDirectionGEY 0x0019+(0x10BC<< 16 ) //DS
#define kDiffusionDirectionGEZ 0x0019+(0x10BD<< 16 ) //DS
-#define kStudyInstanceUID 0x0020+(0x000D << 16 )
-#define kSeriesInstanceUID 0x0020+(0x000E << 16 )
-#define kPatientPosition 0x0020+(0x0032 << 16 )
+#define kBandwidthPerPixelPhaseEncode 0x0019+(0x1028<< 16 ) //FD
+#define kStudyID 0x0020+(0x0010 << 16 )
#define kSeriesNum 0x0020+(0x0011 << 16 )
#define kAcquNum 0x0020+(0x0012 << 16 )
#define kImageNum 0x0020+(0x0013 << 16 )
+#define kStudyInstanceUID 0x0020+(0x000D << 16 )
+#define kSeriesInstanceUID 0x0020+(0x000E << 16 )
+#define kPatientPosition 0x0020+(0x0032 << 16 )
#define kOrientationACR 0x0020+(0x0035 << 16 )
#define kOrientation 0x0020+(0x0037 << 16 )
#define kImagesInAcquisition 0x0020+(0x1002 << 16 ) //IS
@@ -2595,6 +2616,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
#define kRealWorldSlope 0x0040+uint32_t(0x9225 << 16 ) //IS dicm2nii's SlopInt_6_9
#define kDiffusionBFactorGE 0x0043+(0x1039 << 16 ) //IS dicm2nii's SlopInt_6_9
#define kCoilSiemens 0x0051+(0x100F << 16 )
+#define kImaPATModeText 0x0051+(0x1011 << 16 )
#define kLocationsInAcquisition 0x0054+(0x0081 << 16 )
#define kDoseCalibrationFactor 0x0054+(0x1322<< 16 )
#define kIconImageSequence 0x0088+(0x0200 << 16 )
@@ -2624,7 +2646,6 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
#define kNest 0xFFFE +(0xE000 << 16 ) //Item follows SQ
#define kUnnest 0xFFFE +(0xE00D << 16 ) //ItemDelimitationItem [length defined] http://www.dabsoft.ch/dicom/5/7.5/
#define kUnnest2 0xFFFE +(0xE0DD << 16 )//SequenceDelimitationItem [length undefined]
- dti4D->S[0].sliceTiming = -1.0;
int nest = 0;
double zSpacing = -1.0l; //includes slice thickness plus gap
int locationsInAcquisitionGE = 0;
@@ -2652,13 +2673,27 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
bool is2005140FSQwarned = false; //for buggy Philips
bool isAtFirstPatientPosition = false; //for 3d and 4d files: flag is true for slices at same position as first slice
bool isMosaic = false;
- int phaseEncodingSteps = 0;
int patientPositionNum = 0;
int sqDepth = 0;
float patientPosition[4] = {NAN, NAN, NAN, NAN}; //used to compute slice direction for Philips 4D
float patientPositionEndPhilips[4] = {NAN, NAN, NAN, NAN};
float patientPositionStartPhilips[4] = {NAN, NAN, NAN, NAN};
- while ((d.imageStart == 0) && ((lPos+8) < fileLen)) {
+ while ((d.imageStart == 0) && ((lPos+8+lFileOffset) < fileLen)) {
+ #ifndef myLoadWholeFileToReadHeader //read one segment at a time
+ if ((lPos + 128) > MaxBufferSz) { //avoid overreading the file
+ lFileOffset = lFileOffset + lPos;
+ if ((lFileOffset+MaxBufferSz) > fileLen)
+ MaxBufferSz = fileLen - lFileOffset;
+ fseek(file, lFileOffset, SEEK_SET);
+ size_t sz = fread(buffer, 1, MaxBufferSz, file);
+ if (sz < MaxBufferSz) {
+ printError("Only loaded %zu of %zu bytes for %s\n", sz, MaxBufferSz, fname);
+ fclose(file);
+ return d;
+ }
+ lPos = 0;
+ }
+ #endif
if (d.isLittleEndian)
groupElement = buffer[lPos] | (buffer[lPos+1] << 8) | (buffer[lPos+2] << 16) | (buffer[lPos+3] << 24);
else
@@ -2679,8 +2714,6 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
vr[0] = 'N';
vr[1] = 'A';
if (groupElement == kUnnest2) sqDepth--;
- //if (groupElement == kUnnest2) printMessage("SQend %d\n", sqDepth);
-
//if (groupElement == kUnnest) geiisBug = false; //don't exit if there is a proprietary thumbnail
lLength = 4;
} else if (d.isExplicitVR) {
@@ -2738,7 +2771,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
d.imageBytes = dcmInt(4,&buffer[lPos-4],d.isLittleEndian);
//printMessage("compressed data %d-> %ld\n",d.imageBytes, lPos);
if (d.imageBytes > 128) {
- d.imageStart = (int)lPos;
+ d.imageStart = (int)lPos + (int)lFileOffset;
}
}
if ((isIconImageSequence) && ((groupElement & 0x0028) == 0x0028 )) groupElement = kUnused; //ignore icon dimensions
@@ -2749,7 +2782,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
case kTransferSyntax: {
char transferSyntax[kDICOMStr];
dcmStr (lLength, &buffer[lPos], transferSyntax);
- //printMessage("transfer syntax '%s'\n", transferSyntax);
+ //printMessage("%d transfer syntax>>> '%s'\n", compressFlag, transferSyntax);
if (strcmp(transferSyntax, "1.2.840.10008.1.2.1") == 0)
; //default isExplicitVR=true; //d.isLittleEndian=true
else if (strcmp(transferSyntax, "1.2.840.10008.1.2.4.50") == 0) {
@@ -2826,6 +2859,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
case kInstitutionAddress:
dcmStr(lLength, &buffer[lPos], d.institutionAddress);
break;
+ case kReferringPhysicianName:
+ dcmStr(lLength, &buffer[lPos], d.referringPhysicianName);
+ break;
case kComplexImageComponent:
d.isHasPhase = (buffer[lPos]=='P') && (toupper(buffer[lPos+1]) == 'H');
d.isHasMagnitude = (buffer[lPos]=='M') && (toupper(buffer[lPos+1]) == 'A');
@@ -2893,6 +2929,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
d.CSA.numDti = 1;
}
break;
+ case kBandwidthPerPixelPhaseEncode:
+ d.bandwidthPerPixelPhaseEncode = dcmFloatDouble(lLength, &buffer[lPos],d.isLittleEndian);
+ break;
case kStudyInstanceUID :
dcmStr (lLength, &buffer[lPos], d.studyInstanceUID);
break;
@@ -2933,6 +2972,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
case kInPlanePhaseEncodingDirection:
d.phaseEncodingRC = toupper(buffer[lPos]); //first character is either 'R'ow or 'C'ol
break;
+ case kStudyID:
+ dcmStr (lLength, &buffer[lPos], d.studyID);
+ break;
case kSeriesNum:
d.seriesNum = dcmStrInt(lLength, &buffer[lPos]);
break;
@@ -2960,7 +3002,6 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
break;
case kXYSpacing:
dcmMultiFloat(lLength, (char*)&buffer[lPos], 2, d.xyzMM);
-
break;
case kImageComments:
dcmStr (lLength, &buffer[lPos], d.imageComments);
@@ -2999,11 +3040,21 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
zSpacing = dcmStrFloat(lLength, &buffer[lPos]);
break;
case kPhaseEncodingSteps :
- phaseEncodingSteps = dcmStrInt(lLength, &buffer[lPos]);
+ d.phaseEncodingSteps = dcmStrInt(lLength, &buffer[lPos]);
break;
case kEchoTrainLength :
d.echoTrainLength = dcmStrInt(lLength, &buffer[lPos]);
- // printf(">>>>>>>>>>>>>>>> %d", d.echoTrainLength);
+ break;
+ case kAcquisitionMatrix :
+ if (lLength == 8) {
+ uint16_t acquisitionMatrix[4];
+ dcmMultiShorts(lLength, &buffer[lPos], 4, &acquisitionMatrix[0],d.isLittleEndian); //slice position
+ //phaseEncodingLines stored in either image columns or rows
+ if (acquisitionMatrix[3] > 0)
+ d.phaseEncodingLines = acquisitionMatrix[3];
+ if (acquisitionMatrix[2] > 0)
+ d.phaseEncodingLines = acquisitionMatrix[2];
+ }
break;
case kFlipAngle :
d.flipAngle = dcmStrFloat(lLength, &buffer[lPos]);
@@ -3053,6 +3104,15 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
d.coilNum = 0;
}
break; }
+ case kImaPATModeText : { //e.g. Siemens iPAT x2 listed as "p2"
+ char accelStr[kDICOMStr];
+ dcmStr (lLength, &buffer[lPos], accelStr);
+ char *ptr;
+ dcmStrDigitsOnly(accelStr);
+ d.accelFactPE = (float)strtof(accelStr, &ptr);
+ if (*ptr != '\0')
+ d.accelFactPE = 0.0;
+ break; }
case kLocationsInAcquisition :
d.locationsInAcquisition = dcmInt(lLength,&buffer[lPos],d.isLittleEndian);
break;
@@ -3257,7 +3317,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
case kImageStart:
//if ((!geiisBug) && (!isIconImageSequence)) //do not exit for proprietary thumbnails
if ((d.compressionScheme == kCompressNone ) && (!isIconImageSequence)) //do not exit for proprietary thumbnails
- d.imageStart = (int)lPos;
+ d.imageStart = (int)lPos + (int)lFileOffset;
//geiisBug = false;
//http://www.dclunie.com/medical-image-faq/html/part6.html
//unlike raw data, Encapsulated data is stored as Fragments contained in Items that are the Value field of Pixel Data
@@ -3270,20 +3330,19 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
case kImageStartFloat:
d.isFloat = true;
if (!isIconImageSequence) //do not exit for proprietary thumbnails
- d.imageStart = (int)lPos;
+ d.imageStart = (int)lPos + (int)lFileOffset;
isIconImageSequence = false;
break;
case kImageStartDouble:
printWarning("Double-precision DICOM conversion untested: please provide samples to developer\n");
d.isFloat = true;
if (!isIconImageSequence) //do not exit for proprietary thumbnails
- d.imageStart = (int)lPos;
+ d.imageStart = (int)lPos + (int)lFileOffset;
isIconImageSequence = false;
break;
} //switch/case for groupElement
} //if nest
- //#ifdef MY_DEBUG
if (isVerbose > 1) {
if ((lLength > 12) && (lLength < 128)) { //if length is greater than 8 bytes (+4 hdr) the data must be a string [or image data]
char tagStr[kDICOMStr];
@@ -3297,12 +3356,11 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
|| (tagStr[pos] == '*') || (tagStr[pos] == '|') || (tagStr[pos] == '?'))
tagStr[pos] = 'x';
}
- printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\t%s\n", groupElement & 65535,groupElement>>16, lLength, lPos, tagStr);
+ printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\t%s\n", groupElement & 65535,groupElement>>16, lLength, lFileOffset+lPos, tagStr);
//printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\t%s\n", groupElement & 65535,groupElement>>16, lLength, lPos, nest, tagStr);
} else
- printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\n", groupElement & 65535,groupElement>>16, lLength, lPos, nest);
+ printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\n", groupElement & 65535,groupElement>>16, lLength, lFileOffset+lPos, nest);
} //printMessage(" tag=%04x,%04x length=%u pos=%ld %c%c nest=%d\n", groupElement & 65535,groupElement>>16, lLength, lPos,vr[0], vr[1], nest);
- //#endif
lPos = lPos + (lLength);
//printMessage("%d\n",d.imageStart);
} //while d.imageStart == 0
@@ -3367,8 +3425,8 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
printError("Unable to decode %d-bit images with Transfer Syntax 1.2.840.10008.1.2.4.51, decompress with dcmdjpg\n", d.bitsAllocated);
d.isValid = false;
}
- if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (isMosaic) && (d.CSA.mosaicSlices < 1) && (phaseEncodingSteps > 0) && ((d.xyzDim[1] % phaseEncodingSteps) == 0) && ((d.xyzDim[2] % phaseEncodingSteps) == 0) ) {
- d.CSA.mosaicSlices = (d.xyzDim[1] / phaseEncodingSteps) * (d.xyzDim[2] / phaseEncodingSteps);
+ if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (isMosaic) && (d.CSA.mosaicSlices < 1) && (d.phaseEncodingSteps > 0) && ((d.xyzDim[1] % d.phaseEncodingSteps) == 0) && ((d.xyzDim[2] % d.phaseEncodingSteps) == 0) ) {
+ d.CSA.mosaicSlices = (d.xyzDim[1] / d.phaseEncodingSteps) * (d.xyzDim[2] / d.phaseEncodingSteps);
printWarning("Mosaic inferred without CSA header (check number of slices and spatial orientation)\n");
}
if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (d.CSA.dtiV[1] < -1.0) && (d.CSA.dtiV[2] < -1.0) && (d.CSA.dtiV[3] < -1.0))
@@ -3410,6 +3468,10 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
d.CSA.numDti = 0;
}
//d.isValid = false; //debug only - will not create output!
+ #ifndef myLoadWholeFileToReadHeader
+ fclose(file);
+ #endif
+ //printMessage("buffer usage %d %d %d\n",d.imageStart, lPos+lFileOffset, MaxBufferSz);
return d;
} // readDICOM()
@@ -3418,5 +3480,3 @@ struct TDICOMdata readDICOM(char * fname) {
return readDICOMv(fname, false, 0, &unused);
} // readDICOM()
-
-
diff --git a/console/nii_dicom.h b/console/nii_dicom.h
index 8d1b50a..276ca4d 100644
--- a/console/nii_dicom.h
+++ b/console/nii_dicom.h
@@ -38,8 +38,9 @@ extern "C" {
#define kCCsuf " CompilerNA" //unknown compiler!
#endif
- #define kDCMvers "v1.0.20170528" kDCMsuf kCCsuf
+ #define kDCMvers "v1.0.20170624" kDCMsuf kCCsuf
+static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens Mosaic
static const int kMaxDTI4D = 4096; //maximum number of DTI directions for 4D (Philips) images, also maximum number of 3D slices for Philips 3D and 4D images
#define kDICOMStr 64
#define kMANUFACTURER_UNKNOWN 0
@@ -58,7 +59,6 @@ static const int kCompressC3 = 2; //obsolete JPEG lossless
static const int kCompress50 = 3; //obsolete JPEG lossy
struct TDTI {
float V[4];
- float sliceTiming;
int sliceNumberMrPhilips;
};
struct TDTI4D {
@@ -93,21 +93,21 @@ static const int kCompress50 = 3; //obsolete JPEG lossy
#endif
struct TCSAdata {
bool isPhaseMap;
- float dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
+ float sliceTiming[kMaxEPI3D], dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
int numDti, SeriesHeader_offset, SeriesHeader_length, multiBandFactor, sliceOrder, slice_start, slice_end, mosaicSlices,protocolSliceNumber1,phaseEncodingDirectionPositive;
};
struct TDICOMdata {
long seriesNum;
int xyzDim[5];
- int echoTrainLength, patientPositionNumPhilips, coilNum, echoNum, sliceOrient,numberOfDynamicScans, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,patientPositionSequentialRepeats,locationsInAcquisition, compressionScheme;
- float flipAngle, fieldStrength, TE, TI, TR, intenScale, intenIntercept, intenScalePhilips, gantryTilt, lastScanLoc, angulation[4];
+ int phaseEncodingLines, phaseEncodingSteps, echoTrainLength, patientPositionNumPhilips, coilNum, echoNum, sliceOrient,numberOfDynamicScans, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,patientPositionSequentialRepeats,locationsInAcquisition, compressionScheme;
+ float accelFactPE, flipAngle, fieldStrength, TE, TI, TR, intenScale, intenIntercept, intenScalePhilips, gantryTilt, lastScanLoc, angulation[4];
float orient[7], patientPosition[4], patientPositionLast[4], xyzMM[4], stackOffcentre[4];
float radionuclidePositronFraction, radionuclideTotalDose, radionuclideHalfLife, doseCalibrationFactor; //PET ISOTOPE MODULE ATTRIBUTES (C.8-57)
float ecat_isotope_halflife, ecat_dosage;
- double dateTime, acquisitionTime, acquisitionDate;
+ double dateTime, acquisitionTime, acquisitionDate, bandwidthPerPixelPhaseEncode;
bool isXRay, isMultiEcho, isSlicesSpatiallySequentialPhilips, isNonImage, isValid, is3DAcq, isExplicitVR, isLittleEndian, isPlanarRGB, isSigned, isHasPhase,isHasMagnitude,isHasMixed, isFloat, isResampled;
char phaseEncodingRC;
- char softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionAddress[kDICOMStr], institutionName[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageType[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr],seriesDescription[kDICOMStr], sequenceName[kDICOMStr], protocolName[kDICOMStr],sequenceVariant[kDICOMStr],s [...]
+ char softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionAddress[kDICOMStr], institutionName[kDICOMStr], referringPhysicianName[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageType[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr],seriesDescription[kDICOMStr], studyID[kDICOMStr], sequenceName[kDICOMStr [...]
struct TCSAdata CSA;
};
diff --git a/console/nii_dicom_batch.cpp b/console/nii_dicom_batch.cpp
index 86386e1..1c1ea16 100755
--- a/console/nii_dicom_batch.cpp
+++ b/console/nii_dicom_batch.cpp
@@ -332,7 +332,12 @@ bool isDerived(struct TDICOMdata d) {
return true;
}
-#ifdef _MSC_VER
+#ifdef myReadAsciiCsa
+//read from the ASCII portion of the Siemens CSA series header
+// this is not recommended: poorly documented
+// it is better to stick to the binary portion of the Siemens CSA image header
+
+#if defined(_WIN64) || defined(_WIN32)
//https://opensource.apple.com/source/Libc/Libc-1044.1.2/string/FreeBSD/memmem.c
/*-
* Copyright (c) 2005 Pascal Gloor <pascal.gloor at spale.com>
@@ -475,6 +480,8 @@ int siemensEchoEPIFactor(const char * filename, int csaOffset, int csaLength, i
return ret;
}
+#endif //myReadAsciiCsa
+
void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts, struct TDTI4D *dti4D, struct nifti_1_header *h, const char * filename) {
//https://docs.google.com/document/d/1HFUkAEE-pB-angVcYe6pf_-fVf4sCpOHKesUvfb8Grc/edit#
// Generate Brain Imaging Data Structure (BIDS) info
@@ -508,22 +515,34 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,
fprintf(fp, "\t\"SeriesInstanceUID\": \"%s\",\n", d.seriesInstanceUID );
if (strlen(d.studyInstanceUID) > 0)
fprintf(fp, "\t\"StudyInstanceUID\": \"%s\",\n", d.studyInstanceUID );
+ if (strlen(d.referringPhysicianName) > 0)
+ fprintf(fp, "\t\"ReferringPhysicianName\": \"%s\",\n", d.referringPhysicianName );
+ if (strlen(d.studyID) > 0)
+ fprintf(fp, "\t\"StudyID\": \"%s\",\n", d.studyID );
+ //Next lines directly reveal patient identity
+ //if (strlen(d.patientName) > 0)
+ // fprintf(fp, "\t\"PatientName\": \"%s\",\n", d.patientName );
+ //if (strlen(d.patientID) > 0)
+ // fprintf(fp, "\t\"PatientID\": \"%s\",\n", d.patientID );
}
- //printMessage("-->%d %d %s\n", d.CSA.SeriesHeader_offset, d.CSA.SeriesHeader_length, filename);
+ #ifdef myReadAsciiCsa
if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (d.CSA.SeriesHeader_offset > 0) && (d.CSA.SeriesHeader_length > 0) &&
(strlen(d.scanningSequence) > 1) && (d.scanningSequence[0] == 'E') && (d.scanningSequence[1] == 'P')) { //for EPI scans only
int echoSpacing, echoTrainDuration, epiFactor;
epiFactor = siemensEchoEPIFactor(filename, d.CSA.SeriesHeader_offset, d.CSA.SeriesHeader_length, &echoSpacing, &echoTrainDuration);
//printMessage("ES %d ETD %d EPI %d\n", echoSpacing, echoTrainDuration, epiFactor);
if (echoSpacing > 0)
- fprintf(fp, "\t\"EchoSpacing\": %d,\n", echoSpacing);
+ fprintf(fp, "\t\"EchoSpacing\": %g,\n", echoSpacing / 1000000.0); //usec -> sec
if (echoTrainDuration > 0)
- fprintf(fp, "\t\"EchoTrainDuration\": %d,\n", echoTrainDuration);
+ fprintf(fp, "\t\"EchoTrainDuration\": %g,\n", echoTrainDuration / 1000000.0); //usec -> sec
if (epiFactor > 0)
fprintf(fp, "\t\"EPIFactor\": %d,\n", epiFactor);
}
+ #endif
if (d.echoTrainLength > 1) //>1 as for Siemens EPI this is 1, Siemens uses EPI factor http://mriquestions.com/echo-planar-imaging.html
fprintf(fp, "\t\"EchoTrainLength\": %d,\n", d.echoTrainLength);
+ if (d.echoNum > 1)
+ fprintf(fp, "\t\"EchoNumber\": %d,\n", d.echoNum);
if (d.isNonImage) //DICOM is derived image or non-spatial file (sounds, etc)
fprintf(fp, "\t\"RawImage\": false,\n");
if (d.acquNum > 0)
@@ -531,7 +550,7 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,
if (strlen(d.institutionName) > 0)
fprintf(fp, "\t\"InstitutionName\": \"%s\",\n", d.institutionName );
if (strlen(d.institutionAddress) > 0)
- fprintf(fp, "\t\"InstitutionName\": \"%s\",\n", d.institutionAddress );
+ fprintf(fp, "\t\"InstitutionAddress\": \"%s\",\n", d.institutionAddress );
if (strlen(d.deviceSerialNumber) > 0)
fprintf(fp, "\t\"DeviceSerialNumber\": \"%s\",\n", d.deviceSerialNumber );
if (strlen(d.softwareVersions) > 0)
@@ -613,29 +632,45 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,
if (d.TI > 0.0) fprintf(fp, "\t\"InversionTime\": %g,\n", d.TI / 1000.0 );
if (d.ecat_isotope_halflife > 0.0) fprintf(fp, "\t\"IsotopeHalfLife\": %g,\n", d.ecat_isotope_halflife);
if (d.ecat_dosage > 0.0) fprintf(fp, "\t\"Dosage\": %g,\n", d.ecat_dosage);
- //fprintf(fp, "\t\"XXXX\": %g,\n", d.CSA.bandwidthPerPixelPhaseEncode );
- if ((d.CSA.bandwidthPerPixelPhaseEncode > 0.0) && (h->dim[2] > 0) && (h->dim[1] > 0)) {
- float dwellTime = 0.0f;
+ double bandwidthPerPixelPhaseEncode = d.bandwidthPerPixelPhaseEncode;
+ int phaseEncodingLines = d.phaseEncodingLines;
+ if ((phaseEncodingLines == 0) && (h->dim[2] > 0) && (h->dim[1] > 0)) {
if (h->dim[2] == h->dim[2]) //phase encoding does not matter
- dwellTime = 1.0/d.CSA.bandwidthPerPixelPhaseEncode/h->dim[2];
+ phaseEncodingLines = h->dim[2];
else if (d.phaseEncodingRC =='R')
- dwellTime = 1.0/d.CSA.bandwidthPerPixelPhaseEncode/h->dim[2];
+ phaseEncodingLines = h->dim[2];
else if (d.phaseEncodingRC =='C')
- dwellTime = 1.0/d.CSA.bandwidthPerPixelPhaseEncode/h->dim[1];
- if (dwellTime != 0.0f) //as long as phase encoding = R or C or does not matter
- fprintf(fp, "\t\"EffectiveEchoSpacing\": %g,\n", dwellTime );
- }
- bool first = 1;
- if (dti4D->S[0].sliceTiming >= 0.0) {
+ phaseEncodingLines = h->dim[1];
+ }
+ if (bandwidthPerPixelPhaseEncode == 0.0)
+ bandwidthPerPixelPhaseEncode = d.CSA.bandwidthPerPixelPhaseEncode;
+ if (phaseEncodingLines > 0.0) fprintf(fp, "\t\"PhaseEncodingLines\": %d,\n", phaseEncodingLines );
+ if (bandwidthPerPixelPhaseEncode > 0.0)
+ fprintf(fp, "\t\"BandwidthPerPixelPhaseEncode\": %g,\n", bandwidthPerPixelPhaseEncode );
+ double effectiveEchoSpacing = 0.0;
+ if ((phaseEncodingLines > 0) && (bandwidthPerPixelPhaseEncode > 0.0))
+ effectiveEchoSpacing = 1.0 / (bandwidthPerPixelPhaseEncode * phaseEncodingLines) ;
+ if (effectiveEchoSpacing > 0.0)
+ fprintf(fp, "\t\"EffectiveEchoSpacing\": %g,\n", effectiveEchoSpacing);
+ //FSL definition is start of first line until start of last line, so n-1 unless accelerated in-plane acquisition
+ // to check: partial Fourier, iPAT, etc.
+ int fencePost = 1;
+ if (d.accelFactPE > 1.0)
+ fencePost = (int)round(d.accelFactPE); //e.g. if 64 lines with iPAT=2, we want time from start of first until start of 62nd effective line
+ if ((d.phaseEncodingSteps > 1) && (effectiveEchoSpacing > 0.0))
+ fprintf(fp, "\t\"TotalReadoutTime\": %g,\n", effectiveEchoSpacing * ((float)d.phaseEncodingSteps - fencePost));
+ if (d.accelFactPE > 1.0) {
+ fprintf(fp, "\t\"AccelFactPE\": %g,\n", d.accelFactPE);
+ if (effectiveEchoSpacing > 0.0)
+ fprintf(fp, "\t\"TrueEchoSpacing\": %g,\n", effectiveEchoSpacing * d.accelFactPE);
+ }
+ if (d.CSA.sliceTiming[0] >= 0.0) {
fprintf(fp, "\t\"SliceTiming\": [\n");
- for (int i = 0; i < kMaxDTI4D; i++) {
- if (dti4D->S[i].sliceTiming >= 0.0){
- if (!first)
- fprintf(fp, ",\n");
- else
- first = 0;
- fprintf(fp, "\t\t%g", dti4D->S[i].sliceTiming / 1000.0 );
- }
+ for (int i = 0; i < kMaxEPI3D; i++) {
+ if (d.CSA.sliceTiming[i] < 0.0) break;
+ if (i != 0)
+ fprintf(fp, ",\n");
+ fprintf(fp, "\t\t%g", d.CSA.sliceTiming[i] / 1000.0 );
}
fprintf(fp, "\t],\n");
}
@@ -1045,6 +1080,8 @@ int nii_createFilename(struct TDICOMdata dcm, char * niiFilename, struct TDCMopt
printWarning("Ignoring '%%u' in output filename (recompile to segment by acquisition)\n");
#endif
}
+ if (f == 'X')
+ strcat (outname,dcm.studyID);
if (f == 'Z')
strcat (outname,dcm.sequenceName);
if ((f >= '0') && (f <= '9')) {
diff --git a/console/nii_foreign.cpp b/console/nii_foreign.cpp
index 97ad9dc..13989be 100644
--- a/console/nii_foreign.cpp
+++ b/console/nii_foreign.cpp
@@ -400,7 +400,6 @@ int convert_foreign (const char *fn, struct TDCMopts opts){
printMessage("Saving ECAT as '%s'\n", niiFilename);
if (ret != EXIT_SUCCESS) return ret;
struct TDTI4D dti4D;
- dti4D.S[0].sliceTiming = -1.0;
nii_SaveBIDS(niiFilename, dcm, opts, &dti4D, &hdr, fn);
ret = nii_saveNII(niiFilename, hdr, img, opts);
free(img);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/dcm2niix.git
More information about the debian-med-commit
mailing list