DcmDict is a Ruby gem (dcm_dict) to handle in a simple way the Data Dictionary defined within the DICOM® Standard 1 such as DICOM Data Elements or DICOM Unique Identifiers.
With the new releases from year 2014 DICOM documents are available in different format including one particularly interesting, the DocBook XML version.
As confirmed in the DICOM® Standard web site where each part is published in multiple formats and XML format is defined by:
"... XML – good for machine readability, e.g. self-updating validators ..."
This is great news for anyone involved in the study of the standard !
Starting from this thing was born the idea of trying to automate the extraction of data from XML documents to make available the information in a simple way that simplifies the study of the DICOM standard, in the hope this idea will be useful and inspiration.
The library involve String, Array and Symbol class as refinements to access to DICOM information.
In this way is possible to play with the 'Patient's Birth Date' tag defined as (0010,0030) by:
> "(0010,0030)".tag_name
=> "Patient's Birth Date"
> 'PatientBirthDate'.tag_vr
=> [:DA]
> "Patient's Birth Date".tag_vm
=> ["1"]
> :patient_birth_date.tag
=> [16, 48]
> [16,48].tag_key
=> "PatientBirthDate"
> [16, 48].tag_group
=> 16
> '00100030'.tag_element
=> 48
> :patient_birth_date.tag_group
=> 16
> "Patient's Birth Date".tag_element
=> 48
as well for UIDs
> '1.2.840.10008.1.2'.uid_name
=> "Implicit VR Little Endian: Default Transfer Syntax for DICOM"
> '1.2.840.10008.1.2'.uid_type
=> :transfer_syntax
> "Implicit VR Little Endian: Default Transfer Syntax for DICOM".uid_value
=> "1.2.840.10008.1.2"
> "Verification SOP Class".uid_value
=> "1.2.840.10008.1.1"
> "1.2.840.10008.1.1".uid_type
=> :sop_class
> "Verification".uid
=> "1.2.840.10008.1.1"
> :verification.uid
=> "1.2.840.10008.1.1"
let see all features in detail:
The library involve Ruby Refinements so use it is simple, it is necessary to include the specific using directive:
using DcmDict::Refine::StringRefine
for the String object,
using DcmDict::Refine::ArrayRefine
for the Array object and
using DcmDict::Refine::SymbolRefine
for the Symbol object.
That's it.
Note: It is possible to use also the the monkey patching way, this is a deprecated utilization but possible, and, may be, useful technique in certain contexts or for some particular test. For the monkey patching is possible to include some specific common modules in the class you want to use as "keyword": there are two base modules DcmDict::Refine::DataElementRefine and DcmDict::Refine::UidRefine.
For example in the String class will have the code:
class String
include DcmDict::Refine::DataElementRefine
include DcmDict::Refine::UidRefine
end
The main way remains Ruby Refinements.
MRI Ruby: from version v0.51.0 gemspec are changed: the minimum required version is 3.0 in order to manage the refinements changes that occurred in version 3.2:
- The include/extend in refinements never worked (ref Bug #17429)
- import_methods is limited in functionality (ref class Refinement)
Other Rubies: the other considered rubies is only Rubinius checked at version v2.2.10.
Test Note: In order to try to ensure a minimum compatibility there is a file under lib/dcm_dict/rubies/ called rb_ext.rb able to mask/simulates the refinements by refine gem and add the required bit_length method to Fixnum class by backports gem. This sort of extension is not loaded by default but only into spec files for the 'rbx' Ruby Engine. See spec_helper.rb and rb_ext.rb for details.
Any Data Element feature can be accessed from a String, Array or Symbol objects.
For these objects is possible to access to Tag (group/element), Name, Keyword, Value Representation (VR) and Value Multiplicity (VM) for any single Data Element.
The main methods supported are:
Method | Note | Type | |
---|---|---|---|
tag | tag as Array | Array of two Fixnum | (alias of tag_ary) |
tag_name | name of tag | String | |
tag_keyword | keyword | String | |
tag_key | keyword | String | |
tag_vr | Value Representation | Array of Symbol | |
tag_vm | Value Multiplicity | Array of Symbol | |
tag_ps | tag as string (as standard doc) | String | |
tag_ary | tag as Array | Array of two Fixnum | |
tag_sym | tag as Symbol | Symbol | |
tag_ndm | tag as in Native DICOM Model | String | |
tag_str | tag as string (similar to tag_ps) | String | |
tag_note | tag note | String | |
tag_multiple? | is a multiple tag ? | boolean | (useful for 'multi tag' attribute) |
each data element is indexed by these fields:
Field | Type |
---|---|
tag_key | String |
tag_ps | String |
tag_ary | Array |
tag_sym | Symbol |
tag_ndm | String |
tag_str | String |
tag_name | String |
By these fields is possible to access to data element informations. Consider the case of the tag (0010,1005) (Patient's Birth Name), the primary fields are: '(0010,1005)', "Patient's Birth Name", 'PatientBirthName', :patient_birth_name, '00101005' and [0x0010,0x1005]
- As String key you may use the standard tag format '(0010,1005)', the tag name 'Patient's Birth Name', the tag keyword 'PatientBirthName' or the Native DICOM Format tag '00101005'
- As Array key you may use the numeric array [0x0010,0x1005]
- As Symbol key you may use :patient_birth_name
Consider the previous case of tag (0010,1005), the code:
puts "Patient's Birth Name".tag_ps.inspect
puts [0x0010,0x1005].tag_name.inspect
puts '(0010,1005)'.tag_key.inspect
puts :patient_birth_name.tag_vr.inspect
puts 'PatientBirthName'.tag_vm.inspect
puts '00101005'.tag.inspect
puts '(0010,1005)'.tag_ary.inspect
puts '00101005'.tag_sym.inspect
puts 'PatientBirthName'.tag_ndm.inspect
puts "Patient's Birth Name".tag_str.inspect
puts [0x0010,0x1005].tag_note.inspect
puts [0x0010,0x1005].tag_group.inspect
puts :patient_birth_name.tag_element.inspect
will produce
"(0010,1005)"
"Patient's Birth Name"
"PatientBirthName"
[:PN]
["1"]
[16, 4101]
[16, 4101]
:patient_birth_name
"00101005"
"(0010,1005)"
""
16
4101
The library also manage 'multiple tags' such as (0020,31XX) (Source Image IDs). As an example for this data element the default tag in array form is [0x0020,0x3122] and all fields are expressed as:
Method/field | Value |
---|---|
tag | [0x0020,0x3122] |
tag_name | "Source Image IDs" |
tag_keyword | 'SourceImageIDs' |
tag_key | 'SourceImageIDs' |
tag_vr | [:CS] |
tag_vm | ["1-n"] |
tag_ps | '(0020,31XX)' |
tag_ary | [0x0020,0x3122] |
tag_sym | :source_image_ids |
tag_ndm | '00203122' |
tag_str | '(0020,3122)' |
tag_note | 'RET' |
tag_multiple? | true |
[0x0020,0x3122] is the default value for group/element pair ([32, 12578]), but any valid pair of numbers for this tag will be refers that information:
> '(0020,31XX)'.tag_name
=> "Source Image IDs"
> '(0020,31XX)'.tag_ndm
=> "00203122"
> "SourceImageIDs".tag_ary
=> [32, 12578]
> '(0020,3178)'.tag_name
=> "Source Image IDs"
[0x0020,0x3146].tag_sym
=> :source_image_ids
> '00203120'.tag_key
=> "SourceImageIDs"
> [0x0020,0x3138].tag_vr
=> [:CS]
> '(0020,3144)'.tag_note
=> "RET"
and so on.
Any UID features can be accessed from a String or a Symbol object.
For these objects is possible to access to value, name and type values for any single uid. Main methods supported are:
Method | Note | Type | |
---|---|---|---|
uid | value of uid | String | (alias of uid_value) |
uid_value | value of uid | String | |
uid_name | name of uid | String | |
uid_key | keyword of uid | String | |
uid_sym | keyword as symbol of uid | Symbol | |
uid_type | type of uid | Symbol |
each uid is indexed by:
Field | Type |
---|---|
uid_value | String |
uid_name | String |
uid_key | String |
uid_sym | Symbol |
From these fields is possible to access to all uid informations. Consider the case of the uid 1.2.840.10008.1.1 (Verification SOP Class), the primary fields are the strings '1.2.840.10008.1.1', "Verification SOP Class", "Verification".
- As key you may use the standard value '1.2.840.10008.1.1', the uid name "Verification SOP Class", the uid keyword "Verification" and the symbol :verification
For this uid all fields are expressed as:
Method/field | Value |
---|---|
uid | '1.2.840.10008.1.1' |
uid_value | '1.2.840.10008.1.1' |
uid_name | "Verification SOP Class" |
uid_key | "Verification" |
uid_sym | :verification |
uid_type | :sop_class |
> "Verification SOP Class".uid_value
=> "1.2.840.10008.1.1"
> "1.2.840.10008.1.1".uid_type
=> :sop_class
> "1.2.840.10008.1.1".uid_name
=> "Verification SOP Class"
> "Verification SOP Class".uid
=> "1.2.840.10008.1.1"
> "Verification".uid
=> "1.2.840.10008.1.1"
> :verification.uid
=> "1.2.840.10008.1.1"
The library also contains a script (dcm_dict_converter.rb in the bin folder) able to download the xml documents and extracts the source data in a Ruby compatible format. The script produces the conversion in the stdout so for example is possible to extract the Tag Values by:
dcm_dict_converter.rb tag > /tmp/tag-dict.rb
Note: the script use the Nokogiri as XML parser if installed as gem, otherwise the standard REXML.
Check the file for other details.
Current library version is aligned to DICOM Base Standard 2024d
$ gem install dcm_dict
Note for Windows users: may be that it is installed a previous version of Ruby 2.1, if RubyInstaller does not provide the official release for the supported version it's still possible to make it manually by clone/download the 'git' version of RubyInstaller and execute the rake command rake ruby21
or equivalent (see RubyInstaller doc for details).
The main idea is that dictionary should include only fixed data defined in the DICOM standard to encode and then make it available in easy way. There are many possible candidates for inclusion in the dictionary, here are some "ideas":
- Directory Record type data
- Well-known Frames of Reference UID Values
- Context Group UID Values
- Standard Color Palettes UID Values
- IOD definition data
- ...
TBD
Copyright (C) 2014-2024 Enrico Rivarola.
See the LICENSE
and COPYING
files for license details.
Ruby gem dcm_dict on RubyGems at rubygems.org/gems/dcm_dict
Main source code repository on github at henrythebuilder/dcm_dict