All notes
Dcmtk

Dcmtk commands


# Find all patients' ID.
findscu -P -k 0008,0052=PATIENT -k PatientID="" -aec DCM4CHEE 192.168.1.1 11112

# Move one patient's data to another PACS.
movescu -P -k 0008,0052=PATIENT -k PatientID="11111111" -aec DCM4CHEE -aem DCM4CHEE2 192.168.1.1 11112

DCMTK

DCMTK needs the environment variable DCMDICTPATH set to the full path of "dicom.dict" file, which contains a full list of DICOM tag and value types.

When using findscu such as in:


findscu --study --call justTest serverName portNum
  1. "--study, or -S", as explained in the man page, indicates to use study root information model. The NEMA page gives three standard Query/Retrieve information models (QIM, RIM): Patient Root, Study Root, Patient/Study Only (which is said to be retired, ok, now only 2 left). The Patient Root QIM has a four level hierarchy: Patient, Study, Series, Composite Object Instance (COI). It is easy to understand like this: for a patient, he/she may have several studies; for each study, it may have several image series, which in turn could contain multiple COI's. Of these 4 levels, patient information entity (IE) and study IE are modality independent. When it comes to Study Root, there are only 3 levels left, e.g. without patient level. The attributes of patients are considered to be attributes of studies.
  2. "--call name, or -aec name". Set called AE title of peer. Application Entities (AE's) – the nodes in the DICOM network, and their name is called AE Title. If omit this option, the findscu command will return an error like
    
    E: Association Rejected:
    E: Result: Rejected Permanent, Source: Service User
    E: Reason: Called AE Title Not Recognized
    

Now it is simple to understand the following command


# 0008,0052: QueryRetrieveLevel
getscu -d -P -k 0008,0052=SERIES -k SeriesInstanceUID=1.2.840.113820.6000.80000500179.1.14051630770.1.1 -aec DCM4CHEE 192.168.10.204 11112

which will fetch the dicom series and store in the current directory.

dcmdump is used to see the meta information in DICOM file.


# Query/Find all studies (-S).
dcmqr [email protected]:11112 -S
# Same as previous one.
# 1.2.840.10008.5.1.4.1.2.2.1 means "Study Root Query/Retrieve in Information Model – FIND"
dcmqr [email protected]:11112 -cfind 1.2.840.10008.5.1.4.1.2.2.1

# -P means "Patient root". "q.dcm" is the query dicom which could be made with dump2dcm. See next example.
findscu -P -aec DCM4CHEE 192.168.10.204 11112 q.dcm

# q.txt Has the following contents
# # query patient names and IDs
# (0008,0052) CS [PATIENT]     # QueryRetrieveLevel
# (0010,0010) PN []            # PatientName
# (0010,0020) LO []            # PatientID
dump2dcm q.txt q.dcm

dump2dcm

http://support.dcmtk.org/docs/dump2dcm.html.


(0008,0020) DA [19921012]            #  8, 1 StudyDate
(0008,0016) UI =MRImageStorage       # 26, 1 SOPClassUID
(0002,0012) UI [1.2.276.0.7230010.100.1.1]
# Multiple values are separated by "\\".
(0020,0032) DS [0.0\\0.0]             #  8, 2 ImagePositionPatient
(0028,0009) AT (3004,000c)           #  4, 1 FrameIncrementPointer
(0028,0010) US 256                   #  4, 1 Rows
(0002,0001) OB 01\\00

Color image shouldn't be get from getInterData()

Ref. The returned array [0..2] points to the three image planes, where each plane is a pointer array composed of Rows * Cols * getInterData()->getCount().

Get raw data

Ref.


// test program for DicomImage::getInterData() 
// -- requires DCMTK version 3.5.4 

#include "dcmtk/config/osconfig.h" 
#include "dcmtk/dcmimgle/dcmimage.h" 
#include "dcmtk/dcmimage/diregist.h"   // Support for color images
#include "dcmtk/dcmdata/dcrledrg.h"	   // Support for RLE images
#include "dcmtk/dcmjpeg/djdecode.h"	   // Support for JPEG images

class DicomCodecRegistration 
{ 
public: 
	DicomCodecRegistration(void) 
	{ 
		// register decompression codecs
		DcmRLEDecoderRegistration::registerCodecs(); 
		DJDecoderRegistration::registerCodecs(); 
	} 
	~DicomCodecRegistration(void) 
	{ 
		// deregister decompression codecs
		DcmRLEDecoderRegistration::cleanup(); 
		DJDecoderRegistration::cleanup(); 
	} 
};

int main(int argc, char *argv[]) 
{ 
   DicomCodecRegistration registerCodecs;
   
	if (argc > 1) 
	{ 
		DicomImage image(argv[1]); 
		if (image.getStatus() == EIS_Normal) 
		{ 
			const DiPixel *pixeldata = image.getInterData(); 
			if (pixeldata != NULL) 
			{ 
				COUT << "number of pixels: " << pixeldata->getCount() << endl; 
			} 
		} else 
			CERR << "cannot load file: " << argv[1] << endl; 
	} 
	return 0; 
}

DCMTK

Compiling DCMTK3.6.1 on IOS with Cmake will get unrecognized xcodeproj file. The culprit is the line 130 in dcmtkPrepare.cmake:


-ADD_DEFINITIONS("-DDCMTK_BUILD_DATE=\\"2013-11-14\\"")
# NOTE: there should be 4 backslashes on each side,
# but highlightjs may show only two... pls see the php source.
+ADD_DEFINITIONS(-DDCMTK_BUILD_DATE="\\"2013-11-14\\"")

I found this reference on DCMTK forum.

Commands

storescu servIP servPort -aec DCM4CHEE dcmFiles

Compile, Compilation

Compile dynamic/shared libs

DCMTK author said this.

When building shared objects containing C++ code, special handling for templates and constructors/destructors of global variables is required. Therefore, on most systems the shared object must be created with the C++ compiler, not with "ld".

If you are using gcc on a platform where the "-shared" flag is supported, the following steps will create a "dynamic" DCMTK: 

1. run rootconf and configure (see the INSTALL file).
2. edit the file 'config/Makefile.def' to include the following settings:
	CFLAGS= -fPIC -O2
	CXXFLAGS= -fPIC -O2
	AR= gcc
	ARFLAGS= -shared -o
	LIBEXT= so
	RANLIB= :
3. build and install the toolkit with "make", "make install" and "make install-lib".
4. make sure that the environment variable LD_LIBRARY_PATH contains the directory where the DCMTK shared objects are installed.

Note: For Mac OS X, "-shared" should be replaced by "-dynamiclib" in step 2.

MacOS

On MacOS, use clang++ to compile DCMTK. Set the environments:

export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
export CXXFLAGS="-stdlib=libc++ -std=c++11"

error: invalid argument '-std=c++11' not allowed with 'C/ObjC'

It is because Makefile uses CXXFLAGS when compiling c files! I have to manually compile those c files with:


cd dcmdata/
find . -name "*.c" -exec /usr/bin/clang -DHAVE_CONFIG_H -DUSE_NULL_SAFE_OFSTRING -DDCMTK_BUILD_IN_PROGRESS  -DNDEBUG  -c -I. -I. -I../include -I../../config/include -I../../ofstd/include -I../../oflog/include -O -I/opt/local/include/libxml2 -D_REENTRANT -D_XOPEN_SOURCE_EXTENDED -D_BSD_SOURCE -D_BSD_COMPAT -D_OSF_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE_EXTENDED -D_BSD_SOURCE -D_BSD_COMPAT -D_OSF_SOURCE -D_DARWIN_C_SOURCE -stdlib=libc++ -std=c99 {} \;

Compilation Error

error: expected nested-name-specifier before β€˜int’

dcmtk/ofstd/ofexbl.h:48:23: error: expected nested-name-specifier before ‘int’ template<typename Bool>

Culprit

Look into "/usr/include/X11/Xlib.h", which defines "#define Bool int". And therefore makes trouble for dcmtk template definition.

Solution

Change "Bool" to "T" in the ofexbl.h as follows:


template<typename Bool>
	inline OFExplicitBool( Bool value,
		typename OFenable_if
		< OFis_same <OFBool, typename OFdecay<Bool>::type>::value
		>::type* = OFnullptr )
	: m_Value( value ) {}

dcmqrscp

Example config:


# Global setting.
NetworkTCPPort  = 11112
MaxPDUSize      = 16384
MaxAssociations = 16
UserName      = wangcf
GroupName     = staff

# SCUs.
HostTable BEGIN
scu1 = (scu1, 127.0.0.1, 5101)
scu2 = (scu2, 127.0.0.1, 5102)
wcf = scu1, scu2
HostTable END

VendorTable BEGIN
"wcf test pacs"   = wcf
VendorTable END

# Set Database.
AETable BEGIN
WCF	/Users/wangcf/wcf/dcmqrscpDB/db RW (20, 1024mb) ANY
AETable END

Run with: dcmqrscp -c path/to/dcmqrscp.cfg port

FAQ

Find studies in a time range

DCMTK forum.


// How to find the dcm file from 01/01/2011 to 01/06/2011?
req.putAndInsertOFStringArray(DCM_StudyDate, "20110101-20110131");
req.putAndInsertOFStringArray(DCM_StudyDate, "20110101-");
req.putAndInsertOFStringArray(DCM_StudyDate, "-20110131");

Make dcmqrscp accept non-standard SOP ClassUID

Observation

Related files

Modification

NOTE: remember to remove compiled libs and apps before compiling again on modification:


rm -rf dcmqrdb/libsrc/libdcmqrdb.a
rm -rf dcmqrdb/apps/dcmqrscp

Storescu upload DICOM with non-standard SOP Class UID

DCMTK forum. Assume you have a DICOM with SOP class UID: 1.3.12.2.1107.5.9.1. You want to send it to PACS with storescu, you first need to modify from /etc/dcmtk/storescu.cfg:


[[TransferSyntaxes]]

[Uncompressed]
TransferSyntax1 = LocalEndianExplicit
TransferSyntax2 = OppositeEndianExplicit
TransferSyntax3 = LittleEndianImplicit

[[PresentationContexts]]

[PrivateSiemensSOPClass] 
PresentationContext1 = VerificationSOPClass\Uncompressed
PresentationContext2 = 1.3.12.2.1107.5.9.1\Uncompressed

[[Profiles]]

[PrivateSiemens]
PresentationContexts = PrivateSiemensSOPClass

Open test PACS:


# -pm: in promiscuous mode. 11113 is the server port.
storescp -pm 11113 -d

Then run:


storescu -aec PACS001 -xf /etc/dcmtk/storescu.cfg PriateSiemens 192.168.1.1 11112 target.dcm

Adding SOP Classes to DCMTK

DCMTK forum. In order to add support for a new SOP class, edit the following files:

pdf2dcm

Actually, it is a executable in dcm4che.