The [README.md file] describes the typical compilation of the software, using the cmake
command. This document introduces advanced methods for compiling and tuning the software.
The design of dcm2niix is fairly modular. In particular, it can be built to use different libraries to handle the decompression and compression of files. It can even be built without these dependencies, resulting in compact software that will be unable to handle compressed images. Beyond the complexity of compiling the software, the only downside to adding optional modules is that the dcm2niix executable size will require a tiny bit more disk space. For example, miniz (GZip support) adds 18kb, NanoJPEG (lossy JPEG support) adds 13kb, CharLS (JPEG-LS support) adds 271kb, and OpenJPEG (JPEG2000 support) adds 192kb.
The first two sections describe using make
and cmake
to build dcm2niix. The subsequent sections provide in depth notes on compiling directly from the command line. Beware that those notes can get outdated as compilers and options evolve. Further, they can make explicit assumptions regarding the location of libraries. You can always run the make
script to see the current typical compile for your system.
To download and compile dcm2niix with make you can run these commands from the command line (remove --branch development
to get the current stable release):
git clone --branch development [email protected]:rordenlab/dcm2niix.git
cd dcm2niix\console
make
The make file supports different build configurations.
command | conifguratio |
---|---|
make | |
make debug | unoptimized code |
make jp2 | JP2000 support |
make noroi | Ignore [overlays](https://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.9.html#:~:text=A%20Region%20of%20Interest%20(ROI,the%20image%20of%20particular%20interest.) |
make sanitize | memory error detector. |
make wasm | WebAssembly |
You can also append prefix(es) to each of these configurations, for example JPEGLS=1 ZLIB=1 make jp2
will use the system zlib, CharLS and OpenJPEG:
prefix | features |
---|---|
JPEGLS=1 | Statically add CharLS library |
ZLIB=1 | Dynamically link to system zlib instead of static miniz |
JNIfTI=0 | compile without jnifti support |
cmake
can automatically aid complex builds. The home page describes typical cmake options.
To download and compile dcm2niix with cmake you can run these commands from the command line (remove --branch development
to get the current stable release; remove -DZLIB_IMPLEMENTATION=Cloudflare
to produce with the miniz compressor, remove -DUSE_JPEGLS=ON
to build without CharLS and remove -DUSE_OPENJPEG=ON
to compile without JPEG2000 support):
git clone --branch development [email protected]:rordenlab/dcm2niix.git
cd dcm2niix
mkdir build && cd build
cmake -DZLIB_IMPLEMENTATION=Cloudflare -DUSE_JPEGLS=ON -DUSE_OPENJPEG=ON ..
make
If you get the following error:
fatal: unable to connect to github.com:
github.com[0: 140.82.121.4]: errno=Connection timed out
This suggests git is unable to connect using ssh. One solution is to use https instead:
git clone --branch development https://github.com/rordenlab/dcm2niix.git
The text below generally describes how to build dcm2niix using the GCC compiler using the g++
command. However, the code is portable and you can use different compilers. For clang/llvm compile using clang++
. If you have the Intel C compiler, you can substitute the icc
command. The code is compatible with Microsoft's VS 2015 or later. For Microsoft's C compiler you would use the cl
command. In theory, the code should support other compilers, but this has not been tested. Be aware that if you do not have gcc installed the g++
command may use a default to a compiler (e.g. clang). To check what compiler was used, run the dcm2niix software: it always reports the version and the compiler used for the build.
Note that in the commands below we increase the stack sizezgit to 16mb, which is larger than the Unix (8mb) and Windows (1mb) defaults.
Some Centos/Redhat may report "/usr/bin/ld: cannot find -lstdc++". This can be resolved by installing static versions of libstdc++: yum install libstdc++-static
.
To compile with debugging symbols, use
cmake -DUSE_OPENJPEG=ON -DCMAKE_CXX_FLAGS=-g .. && make
If we have zlib, we can use it (-lz) and disable miniz (-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 -o dcm2niix -lz -DmyDisableMiniZ g++ -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 -Wl,-stack_size -Wl,3f00000
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 nii_foreign.cpp -o dcm2niix -static-libgcc g++ -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 -Wl,-stack_size -Wl,3f00000
DICOM images can be stored as either raw data or compressed using one of many formats as described by the transfer syntaxes. One of the compressed formats is the lossy classic JPEG format (which is separate from and predates the JPEG2000 and JPEG-LS formats). This software comes with the NanoJPEG library to handle these images. However, you can use the myDisableClassicJPEG
compiler switch to remove this dependency. The resulting executable will be smaller but will not be able to convert images stored with this format.
g++ -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 g++ -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 -Wl,-stack_size -Wl,3f00000
By default, classic JPEG images will be decoded using the compact NanoJPEG decoder. However, the compiler directive myTurboJPEG
will create an executable based on the libjpeg-turbo 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 executable size (for static builds).
g++ -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 -DmyTurboJPEG -I/opt/libjpeg-turbo/include /opt/libjpeg-turbo/lib/libturbojpeg.a g++ -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 -Wl,-stack_size -Wl,3f00000
You can compile dcm2niix to convert DICOM images compressed with the JPEG-LS transfer syntaxes 1.2.840.10008.1.2.4.80 and 1.2.840.10008.1.2.4.81. Decoding this format is handled by the CharLS library, which is included with dcm2niix in the charls
folder. The included code was downloaded from the CharLS website on 6 June 2018. To enable support you will need to include the myEnableJPEGLS
compiler flag as well as a few file sin the charls
folder. Therefore, a minimal compile (with just JPEG-LS and without JPEG2000) should look like this:
g++ -I. -DmyEnableJPEGLS charls/jpegls.cpp charls/jpegmarkersegment.cpp charls/interface.cpp charls/jpegstreamwriter.cpp charls/jpegstreamreader.cpp main_console.cpp nii_foreign.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp -o dcm2niix -DmyDisableOpenJPEG g++ -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 -Wl,-stack_size -Wl,3f00000
Alternatively, you can decompress an image in JPEG-LS to an uncompressed DICOM using gdcmconv (e.g. gdcmconv -w 3691459 3691459.dcm
). Or you can use gdcmconv compress a DICOM to JPEG-LS (e.g. gdcmconv -L 3691459 3691459.dcm
). Alternatively, the DCMTK tool dcmcjpls provides JPEG-LS support.
You can compile dcm2niix to convert DICOM images compressed with the JPEG2000 transfer syntaxes 1.2.840.10008.1.2.4.90 and 1.2.840.10008.1.2.4.91. This is optional, as JPEG2000 is very rare in DICOMs (usually only created by the proprietary DCMJP2K or OsiriX). Due to the challenges discussed below this is a poor choice for archiving DICOM data. Rather than support conversion with dcm2niix, a better solution would be to use DCMJP2K to do a DICOM-to-DICOM conversion to a more widely supported transfer syntax. Unfortunately, JPEG2000 saw poor adoption as a general image format. This situation is unlikely to change, as JPEG2000 only offered incremental benefits over the simpler classic JPEG, and is outperformed by the more recent HEIF. This has implications for DICOM, as there is little active development on libraries to decode JPEG2000. Indeed, the two popular open-source libraries that decode JPEG2000 have serious limitations for processing these images. Some JPEG2000 DICOM images can not be decoded by the default compilation of OpenJPEG library after version 2.1.0. On the other hand, the Jasper library does not handle lossy 16-bit images with good precision.
You can build dcm2niix with JPEG2000 decompression support using OpenJPEG 2.1.0. You will need to have the OpenJPEG library installed (use the package manager of your Linux distribution, Homebrew for macOS, or see here if you want to build it yourself). If you want to use a more recent version of OpenJPEG, it must be custom-compiled with -DOPJ_DISABLE_TPSOT_FIX
compiler flag. I suggest building static libraries where you would download the code and run
cmake -DBUILD_SHARED_LIBS:bool=off -DOPJ_DISABLE_TPSOT_FIX:bool=on .
make
sudo make install
You should then be able to run:
g++ -O3 -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 g++ -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 -Wl,-stack_size -Wl,3f00000
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 options:
#for MacOS
g++ -O3 -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 -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 -Wl,-stack_size -Wl,3f00000
#For older Linux
g++ -O3 -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 g++ -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 -Wl,-stack_size -Wl,3f00000
#For modern Linux
g++ -O3 -s -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 -lpthread -o dcm2niix -I/usr/local/include/openjpeg-2.2 ~/openjpeg-master/build/bin/libopenjp2.a g++ -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 -Wl,-stack_size -Wl,3f00000
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 nii_foreign.cpp -s -o dcm2niix -ljasper -ljpeg g++ -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 -Wl,-stack_size -Wl,3f00000
This software can be compiled with Microsoft's Visual Studio C compiler. This example assumes the compiler is in your path (For Windows 11 you can run the x64 Native Tools Command Prompt
).
Crucially, you will want to set a large stack allocation. This allows dcm2niix to convert a huge number of DICOM images in a single pass (which requires a large amount of memory).
cl /wd4018 /wd4068 /wd4101 /wd4244 /wd4267 /wd4305 /wd4308 /wd4334 /wd4800 /wd4819 /wd4996 base64.cpp cJSON.cpp main_console.cpp nii_foreign.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp /Fe:dcm2niix.exe -DmyDisableOpenJPEG /link /STACK:8388608
On MacOS you can create Universal binaries, that bundle optimized code for different architectures. For example, supporting PowerPC, Intel and Apple Silicon (e.g. M1) CPUs. Further, you can optimize Intel code for either 32-bit or 64-bit operation. More details on Universal binaries and notarization is provided here.
Here is a simple example of creating independent 32-bit and 64-bit executables and then using lipo
to create a single universal executable:
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 -arch i386 -o dcm2niix32 g++ -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 -Wl,-stack_size -Wl,3f00000
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 -o dcm2niix64 g++ -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 -Wl,-stack_size -Wl,3f00000
lipo -create dcm2niix32 dcm2niix64 -o dcm2niix
To validate that the resulting executable supports both architectures type
file ./dcm2niix