.. _siemens_csa: ====================================== Siemens format DICOM with CSA header ====================================== Recent Siemens DICOM images have useful information stored in a private header. We'll call this the *CSA header*. .. _csa-header: CSA header ========== See this Siemens `Syngo DICOM conformance`_ statement, and a GDCM_ `Siemens header dump`_. .. _`Siemens header dump`: http://sourceforge.net/apps/mediawiki/gdcm/index.php?title=Gdcmdump#SIEMENS_CSA_Header .. _`Syngo DICOM conformance`: http://www.medical.siemens.com/siemens/en_GLOBAL/rg_marcom_FBAs/files/brochures/DICOM/rs/syngoImaging_DCS_VB30A_External.pdf The CSA header is stored in DICOM private tags. In the images we are looking at, there are several relevant tags:: (0029, 1008) [CSA Image Header Type] OB: 'IMAGE NUM 4 ' (0029, 1009) [CSA Image Header Version] OB: '20100114' (0029, 1010) [CSA Image Header Info] OB: Array of 11560 bytes (0029, 1018) [CSA Series Header Type] OB: 'MR' (0029, 1019) [CSA Series Header Version] OB: '20100114' (0029, 1020) [CSA Series Header Info] OB: Array of 80248 bytes In our case we want to read the 'CSAImageHeaderInfo'. From the SPM_ (SPM8) code ``spm_dicom_headers.m`` The CSAImageHeaderInfo and the CSA Series Header Info fields are of the same format. The fields can be of two types, CSA1 and CSA2. Both are always little-endian, whatever the machine endian is. The CSA2 format begins with the string 'SV10', the CSA1 format does not. The code below keeps track of the position *within the CSA header stream*. We'll call this ``csa_position``. At this point (after reading the 8 bytes of the header), ``csa_position == 8``. There's a variable that sets the last byte position in the file that is sensibly still CSA header, and we'll call that ``csa_max_pos``. CSA1 ==== Start header ------------ #. n_tags, uint32, number of tags. Number of tags should apparently be between 1 and 128. If this is not true we just abort and move to ``csa_max_pos``. #. unused, uint32, apparently has value 77 Each tag -------- #. name : S64, null terminated string 64 bytes #. vm : int32 #. vr : S4, first 3 characters only #. syngodt : int32 #. nitems : int32 #. xx : int32 - apparently either 77 or 205 ``nitems`` gives the number of items in the tag. The items follow directly after the tag. Each item --------- 1. xx : int32 * 4 . The first of these seems to be the length of the item in bytes, modified as below. At this point SPM does a check, by calculating the length of this item ``item_len`` with ``xx[0]`` - the ``nitems`` of the *first* read tag. If ``item_len`` is less than 0 or greater than ``csa_max_pos-csa_position`` (the remaining number of bytes to read in the whole header) then we break from the item reading loop, setting the value below to ''. Then we calculate ``item_len`` rounded up to the nearest 4 byte boundary tp get ``next_item_pos``. 2. value : uint8, ``item_len``. We set the stream position to ``next_item_pos``. CSA2 ==== Start header ------------ #. hdr_id : S4 == 'SV10' #. unused1 : uint8, 4 #. n_tags, uint32, number of tags. Number of tags should apparently be between 1 and 128. If this is not true we just abort and move to ``csa_max_pos``. #. unused2, uint32, apparently has value 77 Each tag -------- #. name : S64, null terminated string 64 bytes #. vm : int32 #. vr : S4, first 3 characters only #. syngodt : int32 #. nitems : int32 #. xx : int32 - apparently either 77 or 205 ``nitems`` gives the number of items in the tag. The items follow directly after the tag. Each item --------- 1. xx : int32 * 4 . The first of these seems to be the length of the item in bytes, modified as below. Now there's a different length check from CSA1. ``item_len`` is given just by ``xx[1]``. If ``item_len`` > ``csa_max_pos - csa_position`` (the remaining bytes in the header), then we just read the remaining bytes in the header (as above) into ``value`` below, as uint8, move the filepointer to the next 4 byte boundary, and give up reading. 2. value : uint8, ``item_len``. We set the stream position to the next 4 byte boundary. .. include:: ../links_names.txt