dicom 0.6 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,14 @@
1
+ = 0.6.1
2
+
3
+ === 23rd August, 2009
4
+
5
+ * Fixed a bug (introduced in version 0.6) where the creation of new data elements caused an error.
6
+ * Fixed a bug (introduced in version 0.6) where compressed pixel data were no longer detected correctly.
7
+ * Fixed a bug where writing a DICOM file with no path prefix failed.
8
+ * Fixed a bug where creating a new data element in a DICOM file with tag hierarchies gave an invalid DICOM file.
9
+ * Fixed a bug where retrieving a RMagick image from DICOM files containing two sets of image data failed.
10
+
11
+
1
12
  = 0.6
2
13
 
3
14
  === 13th August, 2009
data/DOCUMENTATION CHANGED
@@ -16,240 +16,240 @@ CLASS DLibrary
16
16
 
17
17
  PUBLIC CLASS METHODS
18
18
 
19
- new()
19
+ new()
20
20
 
21
- Initialize a new Library (dictionary) object.
22
- Useful if you want to make a script that reads hundreds or thousands of DICOM files,
23
- because you can save time by loading the library one time at startup instead of
24
- having the library being loaded for each DICOM file being read.
25
- Example:
26
- myLib = DICOM::DLibrary.new
21
+ Initialize a new Library (dictionary) object.
22
+ Useful if you want to make a script that reads hundreds or thousands of DICOM files,
23
+ because you can save time by loading the library one time at startup instead of
24
+ having the library being loaded for each DICOM file being read.
25
+ Example:
26
+ myLib = DICOM::DLibrary.new
27
27
 
28
28
 
29
29
  CLASS DObject
30
30
 
31
31
  PUBLIC CLASS METHODS
32
32
 
33
- new(filename, options={})
33
+ new(filename, options={})
34
34
 
35
- Initialize a new DICOM object.
36
- Example 1: (The simplest way)
37
- require 'dicom'
38
- obj = DICOM::DObject.new("myFile.dcm")
39
- Example 2: (Using a pre-loaded library to speed up reading when reading multiple files)
40
- obj = DICOM::DObject.new("myFile.dcm", :verbose => false, :lib => myLib)
41
- Example 3: (Open an empty DICOM object)
42
- obj = DICOM::DObject.new(nil)
35
+ Initialize a new DICOM object.
36
+ Example 1: (The simplest way)
37
+ require 'dicom'
38
+ obj = DICOM::DObject.new("myFile.dcm")
39
+ Example 2: (Using a pre-loaded library to speed up reading when reading multiple files)
40
+ obj = DICOM::DObject.new("myFile.dcm", :verbose => false, :lib => myLib)
41
+ Example 3: (Open an empty DICOM object)
42
+ obj = DICOM::DObject.new(nil)
43
43
 
44
44
  ACCESSORS (read only)
45
- :read_success
46
- A boolean that is true if DICOM object was read successfully, and false if not.
47
- :write_success
48
- A boolean that is true if DICOM object was written successfully, and false if not.
49
- :errors
50
- An array holding any error messages, warnings or notices that have been logged
51
- during your interaction with DObject.
52
- :modality
53
- A string which holds the description of the modality of the DICOM object that has been read.
54
- Example of use:
55
- obj = DICOM::DObject.new("myFile.dcm")
56
- if obj.read_success
57
- puts obj.modality
58
- end
59
- The following accessors are the arrays that hold all the information gathered on the DICOM object.
60
- As such, their length is equal to the number of tags in a DICOM object.
61
- :names
62
- :tags
63
- :types
64
- :lengths
65
- :values
66
- :raw
67
- :levels
45
+ :read_success
46
+ A boolean that is true if DICOM object was read successfully, and false if not.
47
+ :write_success
48
+ A boolean that is true if DICOM object was written successfully, and false if not.
49
+ :errors
50
+ An array holding any error messages, warnings or notices that have been logged
51
+ during your interaction with DObject.
52
+ :modality
53
+ A string which holds the description of the modality of the DICOM object that has been read.
54
+ Example of use:
55
+ obj = DICOM::DObject.new("myFile.dcm")
56
+ if obj.read_success
57
+ puts obj.modality
58
+ end
59
+ The following accessors are the arrays that hold all the information gathered on the DICOM object.
60
+ As such, their length is equal to the number of tags in a DICOM object.
61
+ :names
62
+ :tags
63
+ :types
64
+ :lengths
65
+ :values
66
+ :raw
67
+ :levels
68
68
 
69
69
  PUBLIC INSTANCE METHODS
70
70
 
71
- children(element, options={})
72
- Returns the positions of all data elements inside the hierarchy of a sequence or an item.
73
- This is useful if you later want to get the position(s) of a certain element,
74
- restricted to the positions inside the given sequence or item.
75
- Element may be an array index, element name or element tag.
76
- Example 1: (Return all element positions that is contained in the following sequence)
77
- pos = obj.children("3006,0082")
78
- Example 2: (Return all element positions that is contained only directly beneath the following sequence)
79
- pos = obj.children("3006,0082", :next_only => true)
80
-
81
- get_frames
82
- Returns the number of frames present in the image data in the DICOM file.
83
-
84
- get_image_magick
85
- Returns an array of RMagick image objects, where the size of the array corresponds
86
- with the number of frames in the image data.
87
- To call this method the user needs to have loaded the RMagick bindings in advance (require 'RMagick').
88
- Example (retrieve object and display first frame):
89
- require 'RMagick'
90
- data = dicom.get_image_magick()
91
- data[0].display
92
-
93
- get_image_narray
94
- Returns a 3d NArray object where the array dimensions are related to [frames, columns, rows].
95
- To call this method the user needs to have loaded the NArray library in advance (require 'narray').
96
- Example (retrieve object and display first frame):
97
- require 'narray'
98
- require 'nimage'
99
- data = obj.get_image_narray()
100
- NImage.show data[0,true,true]
101
-
102
- get_image_pos
103
- Returns the index(es) of the data element(s) that contain image data.
104
-
105
- get_pos(string, options={})
106
- Returns the index(es) of the data element(s) in the DICOM file that match
107
- the supplied element tag or name.
108
- Example 1: (Find all occurences of the specified tag in the object)
109
- pos = obj.get_pos("3006,0080")
110
- Example 2: (Find all occurences of the specified tag inside the specified sequence)
111
- selection = obj.children("3006,0082")
112
- pos = obj.get_pos("3006,0080", :array => selection)
113
- Example 3: (Using the :partial argument to find position of all elements containing a specific string)
114
- pos = obj.get_pos("0010", :partial => true)
115
- pos = obj.get_pos("Name", :partial => true)
116
-
117
- get_raw(element, options={})
118
- Returns the raw data of the requested DICOM data element.
119
- Element may be an array index, element name or element tag.
120
- If you wish to return multiple data values of a tag that occurs several times in the file,
121
- use the keyword :array => true .
122
- Example: (Returns all data values in a array)
123
- contour_data = obj.get_raw("3006,0050", :array => true)
124
-
125
- get_value(element)
126
- Returns the value (processed raw data) of the requested DICOM data element.
127
- Element may be an array index, element name or element tag.
128
- If you wish to return multiple values of a tag that occurs several times in the file,
129
- use the keyword :array => true .
130
- Example: (Returns all data values in a array)
131
- contour_data = obj.get_value("3006,0050", :array => true)
132
-
133
- image_to_file(file)
134
- Dumps the pixel data of the DICOM object directly to the specified file.
135
- This is useful if you wish to extract this data to process it with another program.
136
-
137
- parents(element)
138
- Returns the positions of all parents of this tag in the hierarchy.
139
- This is useful if you want to know the position of the items or sequence tags that 'hold' your tag.
140
- Element may be an array index, element name or element tag.
141
- Example:
142
- pos = obj.parents("300C,0006")
143
-
144
- print(pos, options={})
145
- Prints the information gathered on one or several/all tag(s) in the DICOM object:
146
- (index, [hierarchy level,] label, name, type, length, value)
147
- The method can print to both screen or to a text file. If print to file is chosen,
148
- the text file will be put in the folder of the original DICOM file with a '.txt' extension.
149
- The argument pos may be a number (array position), an array of numbers, or true.
150
- Example 1: (Print all tags to file, with both tree visualization and level numbers)
151
- obj.print(true, :levels => true, :tree => true, :file => true)
152
- Example 2: (Print an array of tags to screen, no level or tree visualization)
153
- obj.print([4,5,6])
154
-
155
- print_all
156
- Prints information of all tags stored in the DICOM object to the screen.
157
-
158
- print_properties
159
- Prints the key structural properties of the DICOM file to the screen.
160
-
161
- remove(element)
162
- Removes the specified data element from the DICOM object. You can use this method
163
- if you are editing a DICOM object and wants to get rid of one or more elements.
164
- Element may be an array index, element name or element tag.
165
-
166
- set_value(value, element, options={})
167
- This method can be used both to edit an existing data element, or to create
168
- new data elements in your DICOM object.
169
- Element may be an array index, element name or element tag.
170
- Example 1: (Edit patient name)
171
- obj.set_value("Anonymous", "0010,0010", :create => false)
172
- Example 2: (Insert binary data for a specific tag)
173
- obj.set_value(data, 52, :bin => true, :create => false)
174
-
175
- set_image_magick(object)
176
- Inserts a RMagick image object to the pixel data tag of your DICOM object.
177
-
178
- set_image_file(file)
179
- Inserts the binary content of a file to the Pixel Data tag in your DICOM object.
180
- This can be useful if you have processed some image data using a custom program
181
- and just wants to put that data back into a DICOM object.
182
-
183
- write(file)
184
- Writes the DICOM object to the specified file.
185
- Example:
186
- obj.write(myPath + "test_file.dcm")
71
+ children(element, options={})
72
+ Returns the positions of all data elements inside the hierarchy of a sequence or an item.
73
+ This is useful if you later want to get the position(s) of a certain element,
74
+ restricted to the positions inside the given sequence or item.
75
+ Element may be an array index, element name or element tag.
76
+ Example 1: (Return all element positions that is contained in the following sequence)
77
+ pos = obj.children("3006,0082")
78
+ Example 2: (Return all element positions that is contained only directly beneath the following sequence)
79
+ pos = obj.children("3006,0082", :next_only => true)
80
+
81
+ get_frames
82
+ Returns the number of frames present in the image data in the DICOM file.
83
+
84
+ get_image_magick
85
+ Returns an array of RMagick image objects, where the size of the array corresponds
86
+ with the number of frames in the image data.
87
+ To call this method the user needs to have loaded the RMagick bindings in advance (require 'RMagick').
88
+ Example (retrieve object and display first frame):
89
+ require 'RMagick'
90
+ data = dicom.get_image_magick()
91
+ data[0].display
92
+
93
+ get_image_narray
94
+ Returns a 3d NArray object where the array dimensions are related to [frames, columns, rows].
95
+ To call this method the user needs to have loaded the NArray library in advance (require 'narray').
96
+ Example (retrieve object and display first frame):
97
+ require 'narray'
98
+ require 'nimage'
99
+ data = obj.get_image_narray()
100
+ NImage.show data[0,true,true]
101
+
102
+ get_image_pos
103
+ Returns the index(es) of the data element(s) that contain image data.
104
+
105
+ get_pos(string, options={})
106
+ Returns the index(es) of the data element(s) in the DICOM file that match
107
+ the supplied element tag or name.
108
+ Example 1: (Find all occurences of the specified tag in the object)
109
+ pos = obj.get_pos("3006,0080")
110
+ Example 2: (Find all occurences of the specified tag inside the specified sequence)
111
+ selection = obj.children("3006,0082")
112
+ pos = obj.get_pos("3006,0080", :array => selection)
113
+ Example 3: (Using the :partial argument to find position of all elements containing a specific string)
114
+ pos = obj.get_pos("0010", :partial => true)
115
+ pos = obj.get_pos("Name", :partial => true)
116
+
117
+ get_raw(element, options={})
118
+ Returns the raw data of the requested DICOM data element.
119
+ Element may be an array index, element name or element tag.
120
+ If you wish to return multiple data values of a tag that occurs several times in the file,
121
+ use the keyword :array => true .
122
+ Example: (Returns all data values in a array)
123
+ contour_data = obj.get_raw("3006,0050", :array => true)
124
+
125
+ get_value(element)
126
+ Returns the value (processed raw data) of the requested DICOM data element.
127
+ Element may be an array index, element name or element tag.
128
+ If you wish to return multiple values of a tag that occurs several times in the file,
129
+ use the keyword :array => true .
130
+ Example: (Returns all data values in a array)
131
+ contour_data = obj.get_value("3006,0050", :array => true)
132
+
133
+ image_to_file(file)
134
+ Dumps the pixel data of the DICOM object directly to the specified file.
135
+ This is useful if you wish to extract this data to process it with another program.
136
+
137
+ parents(element)
138
+ Returns the positions of all parents of this tag in the hierarchy.
139
+ This is useful if you want to know the position of the items or sequence tags that 'hold' your tag.
140
+ Element may be an array index, element name or element tag.
141
+ Example:
142
+ pos = obj.parents("300C,0006")
143
+
144
+ print(pos, options={})
145
+ Prints the information gathered on one or several/all tag(s) in the DICOM object:
146
+ (index, [hierarchy level,] label, name, type, length, value)
147
+ The method can print to both screen or to a text file. If print to file is chosen,
148
+ the text file will be put in the folder of the original DICOM file with a '.txt' extension.
149
+ The argument pos may be a number (array position), an array of numbers, or true.
150
+ Example 1: (Print all tags to file, with both tree visualization and level numbers)
151
+ obj.print(true, :levels => true, :tree => true, :file => true)
152
+ Example 2: (Print an array of tags to screen, no level or tree visualization)
153
+ obj.print([4,5,6])
154
+
155
+ print_all
156
+ Prints information of all tags stored in the DICOM object to the screen.
157
+
158
+ print_properties
159
+ Prints the key structural properties of the DICOM file to the screen.
160
+
161
+ remove(element)
162
+ Removes the specified data element from the DICOM object. You can use this method
163
+ if you are editing a DICOM object and wants to get rid of one or more elements.
164
+ Element may be an array index, element name or element tag.
165
+
166
+ set_value(value, element, options={})
167
+ This method can be used both to edit an existing data element, or to create
168
+ new data elements in your DICOM object.
169
+ Element may be an array index, element name or element tag.
170
+ Example 1: (Edit patient name)
171
+ obj.set_value("Anonymous", "0010,0010", :create => false)
172
+ Example 2: (Insert binary data for a specific tag)
173
+ obj.set_value(data, 52, :bin => true, :create => false)
174
+
175
+ set_image_magick(object)
176
+ Inserts a RMagick image object to the pixel data tag of your DICOM object.
177
+
178
+ set_image_file(file)
179
+ Inserts the binary content of a file to the Pixel Data tag in your DICOM object.
180
+ This can be useful if you have processed some image data using a custom program
181
+ and just wants to put that data back into a DICOM object.
182
+
183
+ write(file)
184
+ Writes the DICOM object to the specified file.
185
+ Example:
186
+ obj.write(myPath + "test_file.dcm")
187
187
 
188
188
 
189
189
  CLASS Anonymizer
190
190
 
191
191
  PUBLIC CLASS METHODS
192
192
 
193
- new()
194
- Initialize a new Anonymizer instance.
195
- Example:
196
- a = DICOM::Anonymizer.new
193
+ new()
194
+ Initialize a new Anonymizer instance.
195
+ Example:
196
+ a = DICOM::Anonymizer.new
197
197
 
198
198
  ACCESSORS (Read & write)
199
- :blank
200
- A boolean that you can set if you want to all anonymization tags to be blank
201
- instead of having some generic value.
202
- :enumeration
203
- A boolean that if set will make the script set enumerated values on anonymized tags,
204
- such that you are able to separate the DICOM files of unique individuals after anonymization.
205
- Example of fictious result:
206
- "Joe Sixpack" => "Person1" and "Joe Schmoe" => "Person2"
207
- :identity_file
208
- If you request enumeration, you can specify an identity file which will enable you to reidentify
209
- the anonymized DICOM files at a later stage. The relationship between original names and
210
- enumerated values is stored in a text file which you can keep for yourself, while handing out
211
- the anonymized DICOM files to a third party.
212
-
213
- :write_path
214
- You may set a different path for where the anonymized DICOM files will be stored. If this
215
- value is not set, the Anonymizer script will overwrite the old DICOM files.
216
- Example:
217
- a.write_path = "C:/temp/"
199
+ :blank
200
+ A boolean that you can set if you want to all anonymization tags to be blank
201
+ instead of having some generic value.
202
+ :enumeration
203
+ A boolean that if set will make the script set enumerated values on anonymized tags,
204
+ such that you are able to separate the DICOM files of unique individuals after anonymization.
205
+ Example of fictious result:
206
+ "Joe Sixpack" => "Person1" and "Joe Schmoe" => "Person2"
207
+ :identity_file
208
+ If you request enumeration, you can specify an identity file which will enable you to reidentify
209
+ the anonymized DICOM files at a later stage. The relationship between original names and
210
+ enumerated values is stored in a text file which you can keep for yourself, while handing out
211
+ the anonymized DICOM files to a third party.
212
+
213
+ :write_path
214
+ You may set a different path for where the anonymized DICOM files will be stored. If this
215
+ value is not set, the Anonymizer script will overwrite the old DICOM files.
216
+ Example:
217
+ a.write_path = "C:/temp/"
218
218
 
219
219
  PUBLIC INSTANCE METHODS
220
220
 
221
- add_folder(path)
222
- Adds a folder who's files (including all files in subfolders) will be anonymized.
223
- Example:
224
- a.add_folder("/home/dicom")
221
+ add_folder(path)
222
+ Adds a folder who's files (including all files in subfolders) will be anonymized.
223
+ Example:
224
+ a.add_folder("/home/dicom")
225
225
 
226
- add_exception(path)
227
- Adds a folder who's files (including all files in its subfolders) will be excluded from anonymization.
226
+ add_exception(path)
227
+ Adds a folder who's files (including all files in its subfolders) will be excluded from anonymization.
228
228
 
229
- add_tag(tag, options={})
230
- Adds a tag to the list of tags that will be anonymized. As options you can specify value to be used
231
- and whether the tag should be included for enumeration if this feature has been activated.
232
- Example:
233
- a.add_tag("0010,0010, :value => "MrAnonymous", :enum => true)
229
+ add_tag(tag, options={})
230
+ Adds a tag to the list of tags that will be anonymized. As options you can specify value to be used
231
+ and whether the tag should be included for enumeration if this feature has been activated.
232
+ Example:
233
+ a.add_tag("0010,0010, :value => "MrAnonymous", :enum => true)
234
234
 
235
- change_enum(tag, status)
236
- Sets enumeration status for a specific tag. Status = true means the selected tag will get
237
- an enumerated value, false means it will not.
235
+ change_enum(tag, status)
236
+ Sets enumeration status for a specific tag. Status = true means the selected tag will get
237
+ an enumerated value, false means it will not.
238
238
 
239
- execute(verbose)
240
- Executes the anonymization process. Run this method when you are finished choosing all your settings.
241
- Verbose (=true/false) will apply to the read/update/write process that takes place in DObject, and not
242
- the messages of the Anonymization script itself.
239
+ execute(verbose)
240
+ Executes the anonymization process. Run this method when you are finished choosing all your settings.
241
+ Verbose (=true/false) will apply to the read/update/write process that takes place in DObject, and not
242
+ the messages of the Anonymization script itself.
243
243
 
244
- print
245
- Prints the list of tags that have been selected for anonymization, along with the values
246
- that the original tags will be replaced with. If enumeration is selected, this method will also
247
- print which tags have been selected for enumeration.
244
+ print
245
+ Prints the list of tags that have been selected for anonymization, along with the values
246
+ that the original tags will be replaced with. If enumeration is selected, this method will also
247
+ print which tags have been selected for enumeration.
248
248
 
249
- remove_tag(tag)
250
- Removes a tag from the list of tags that will be anonymized.
251
- Example:
252
- a.remove_tag("0010,0010")
249
+ remove_tag(tag)
250
+ Removes a tag from the list of tags that will be anonymized.
251
+ Example:
252
+ a.remove_tag("0010,0010")
253
253
 
254
254
 
255
255
  CLASS DClient
@@ -289,7 +289,7 @@ ACCESSORS (Read only)
289
289
  PUBLIC INSTANCE METHODS
290
290
 
291
291
  get_image(path, options={})
292
- Retrieve a DICOM image file from a server (C-GET-RQ) (this method is probably not working yet).
292
+ Retrieve a DICOM image file from a server (C-GET-RQ) (this method is untested (might not work)).
293
293
  Accepted options:
294
294
  "0008,0018" (SOP Instance UID)
295
295
  "0008,0052" (Query/Retrieve Level)
@@ -307,7 +307,7 @@ PUBLIC INSTANCE METHODS
307
307
  "0020,000E" (Series Instance UID)
308
308
  "0020,0013" (Instance Number)
309
309
  Example:
310
- find_images("0010,0020" => patient_id, "0020,000D" => study_uid, "0020,000E" => series_uid)
310
+ result = node.find_images("0010,0020" => patient_id, "0020,000D" => study_uid, "0020,000E" => series_uid)
311
311
 
312
312
  find_patients(options={})
313
313
  Query a server for patients that matches your specified criteria.
@@ -318,7 +318,7 @@ PUBLIC INSTANCE METHODS
318
318
  "0010,0030" (Patient's Birth Date)
319
319
  "0010,0040" (Patient's Sex)
320
320
  Example:
321
- find_patients("0010,0010" => "James*")
321
+ result = node.find_patients("0010,0010" => "James*")
322
322
 
323
323
  find_series(options={})
324
324
  Query a server for series that matches your specified criteria.
@@ -330,7 +330,7 @@ PUBLIC INSTANCE METHODS
330
330
  "0020,000E" (Series Instance UID)
331
331
  "0020,0011" (Series Number)
332
332
  Example:
333
- find_series("0010,0020" => patient_id, "0020,000D" => study_uid)
333
+ result = node.find_series("0010,0020" => patient_id, "0020,000D" => study_uid)
334
334
 
335
335
  find_studies(options={})
336
336
  Query a server for studies that matches your specified criteria.
@@ -349,7 +349,7 @@ PUBLIC INSTANCE METHODS
349
349
  "0020,000D" (Study Instance UID)
350
350
  "0020,0010" (Study ID)
351
351
  Example:
352
- find_studies("0008,0020" => study_date, "0010,000D" => patient_id)
352
+ result = node.find_studies("0008,0020" => study_date, "0010,000D" => patient_id)
353
353
 
354
354
  move_image(destination, options={})
355
355
  Move an image to a dicom node other than yourself.
@@ -359,7 +359,7 @@ PUBLIC INSTANCE METHODS
359
359
  "0020,000D" (Study Instance UID)
360
360
  "0020,000E" (Series Instance UID)
361
361
  Example:
362
- move_image("MYDICOM", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
362
+ node.move_image("MYDICOM", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
363
363
 
364
364
  move_study(destination, options={})
365
365
  Move an entire study to a dicom node other than yourself.
@@ -368,12 +368,12 @@ PUBLIC INSTANCE METHODS
368
368
  "0010,0020" (Patient ID)
369
369
  "0020,000D" (Study Instance UID)
370
370
  Example:
371
- move_study("MYDICOM", "0010,0020" => patient_id, "0020,000D" => study_uid)
371
+ node.move_study("MYDICOM", "0010,0020" => patient_id, "0020,000D" => study_uid)
372
372
 
373
373
  send(file_path)
374
374
  Send a DICOM file to a service class provider (SCP/PACS).
375
375
  Example:
376
- send("myFile.dcm")
376
+ node.send("myFile.dcm")
377
377
 
378
378
  test
379
379
  Tests a connection with your DICOM server by trying a simple association.
@@ -386,7 +386,7 @@ PUBLIC CLASS METHODS
386
386
  new(port, options={})
387
387
  Initialize a new DServer instance.
388
388
  Example:
389
- node = DICOM::DServer.new(104)
389
+ server = DICOM::DServer.new(104)
390
390
 
391
391
  ACCESSORS (Read & write)
392
392
  :host_ae
@@ -420,4 +420,4 @@ PUBLIC INSTANCE METHODS
420
420
  Completely clears the list of syntaxes that the server instance will accept.
421
421
 
422
422
  start_scp(path)
423
- Launch the simple storage server (Storage Content Provider - SCP)
423
+ Launch the simple storage server (Storage Content Provider - SCP).
data/lib/DClient.rb CHANGED
@@ -42,20 +42,6 @@ module DICOM
42
42
  end
43
43
 
44
44
 
45
- # Retrieve a dicom file from a service class provider (SCP/PACS).
46
- # Example: get_image("c:/dicom/", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
47
- def get_image(path, options={})
48
- # Study Root Query/Retrieve Information Model - GET:
49
- @abstract_syntax = "1.2.840.10008.5.1.4.1.2.2.3"
50
- # Transfer the current options to the data_elements hash:
51
- set_command_fragment_get
52
- # Prepare data elements for this operation:
53
- set_data_fragment_get_image
54
- set_data_options(options)
55
- perform_get(path)
56
- end
57
-
58
-
59
45
  # Query a service class provider for images that match the specified criteria.
60
46
  # Example: find_images("0010,0020" => "123456789", "0020,000D" => "1.2.840.1145.342", "0020,000E" => "1.3.6.1.4.1.2452.6.687844") # (Patient ID, Study Instance UID & Series Instance UID)
61
47
  def find_images(options={})
@@ -65,6 +51,7 @@ module DICOM
65
51
  set_data_fragment_find_images
66
52
  set_data_options(options)
67
53
  perform_find
54
+ return @data_results
68
55
  end
69
56
 
70
57
 
@@ -77,6 +64,7 @@ module DICOM
77
64
  set_data_fragment_find_patients
78
65
  set_data_options(options)
79
66
  perform_find
67
+ return @data_results
80
68
  end
81
69
 
82
70
 
@@ -89,6 +77,7 @@ module DICOM
89
77
  set_data_fragment_find_series
90
78
  set_data_options(options)
91
79
  perform_find
80
+ return @data_results
92
81
  end
93
82
 
94
83
 
@@ -101,6 +90,21 @@ module DICOM
101
90
  set_data_fragment_find_studies
102
91
  set_data_options(options)
103
92
  perform_find
93
+ return @data_results
94
+ end
95
+
96
+
97
+ # Retrieve a dicom file from a service class provider (SCP/PACS).
98
+ # Example: get_image("c:/dicom/", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
99
+ def get_image(path, options={})
100
+ # Study Root Query/Retrieve Information Model - GET:
101
+ @abstract_syntax = "1.2.840.10008.5.1.4.1.2.2.3"
102
+ # Transfer the current options to the data_elements hash:
103
+ set_command_fragment_get
104
+ # Prepare data elements for this operation:
105
+ set_data_fragment_get_image
106
+ set_data_options(options)
107
+ perform_get(path)
104
108
  end
105
109
 
106
110
 
data/lib/DLibrary.rb CHANGED
@@ -26,6 +26,36 @@ module DICOM
26
26
  end
27
27
 
28
28
 
29
+ # Checks whether a given string is a valid transfer syntax or not.
30
+ def check_ts_validity(uid)
31
+ result = false
32
+ value = @uid[uid.rstrip]
33
+ if value != nil
34
+ if value[1] == "Transfer Syntax"
35
+ # Proved valid:
36
+ result = true
37
+ end
38
+ end
39
+ return result
40
+ end
41
+
42
+
43
+ # Checks if the supplied transfer syntax indicates the presence of pixel compression or not.
44
+ def get_compression(uid)
45
+ result = false
46
+ if uid
47
+ value = @uid[uid.rstrip]
48
+ if value != nil
49
+ if value[1] == "Transfer Syntax" and not value[0].include?("Endian")
50
+ # It seems we have compression:
51
+ result = true
52
+ end
53
+ end
54
+ end
55
+ return result
56
+ end
57
+
58
+
29
59
  # Returns data element name and value representation from the dictionary if the data element
30
60
  # is recognized, else it returns "Unknown Name" and "UN".
31
61
  def get_name_vr(tag)
@@ -91,20 +121,6 @@ module DICOM
91
121
  end
92
122
 
93
123
 
94
- # Checks whether a given string is a valid transfer syntax or not.
95
- def check_ts_validity(uid)
96
- result = false
97
- value = @uid[uid.rstrip]
98
- if value != nil
99
- if value[1] == "Transfer Syntax"
100
- # Proved valid:
101
- result = true
102
- end
103
- end
104
- return result
105
- end
106
-
107
-
108
124
  # Returns the name/description corresponding to a given UID.
109
125
  def get_uid(uid)
110
126
  value = @uid[uid.rstrip]
@@ -118,22 +134,6 @@ module DICOM
118
134
  end
119
135
 
120
136
 
121
- # Checks if the supplied transfer syntax indicates the presence of pixel compression or not.
122
- def get_compression(uid)
123
- result = false
124
- if uid
125
- value = @uid[uid.rstrip]
126
- if value != nil
127
- if value[1] == "Transfer Syntax" and not value[0].include?("Endian")
128
- # It seems we have compression:
129
- res = true
130
- end
131
- end
132
- end
133
- return result
134
- end
135
-
136
-
137
137
  # Checks the Transfer Syntax UID and return the encoding settings associated with this value.
138
138
  def process_transfer_syntax(value)
139
139
  valid = check_ts_validity(value)
@@ -160,8 +160,8 @@ module DICOM
160
160
  # For everything else, assume compressed pixel data, with Explicit VR, Little Endian:
161
161
  explicit = true
162
162
  endian = false
163
- end
164
- return [valid, explicit, endian]
163
+ end
164
+ return [valid, explicit, endian]
165
165
  end
166
166
 
167
167
 
data/lib/DObject.rb CHANGED
@@ -24,11 +24,11 @@
24
24
  # -Support for color image data to get_image_narray and get_image_magick.
25
25
  # -Complete support for Big endian (basic support is already featured).
26
26
  # -Complete support for multiple frame image data to NArray and RMagick objects (partial support already featured).
27
- # -Reading of image data in files that contain two different and unrelated images (this problem has been observed with some MR images).
27
+ # -Make the image handling more intelligent with respect to interpreting data elements that hold information on the image and its properties.
28
28
 
29
29
  module DICOM
30
30
 
31
- # Class for handling the DICOM contents:
31
+ # Class for interacting with the DICOM object.
32
32
  class DObject
33
33
 
34
34
  attr_reader :read_success, :write_success, :modality, :errors, :segments,
@@ -172,9 +172,9 @@ module DICOM
172
172
  add_msg("Error: Method read_image_magick does not have enough data available to build an image object.")
173
173
  return false
174
174
  end
175
- if @compression != true
175
+ unless @compression
176
176
  # Non-compressed, just return the array contained on the particular element:
177
- image_data=get_pixels(pos)
177
+ image_data = get_pixels(pos)
178
178
  image = Magick::Image.new(columns,rows)
179
179
  image.import_pixels(0, 0, columns, rows, "I", image_data)
180
180
  return image
@@ -192,7 +192,7 @@ module DICOM
192
192
 
193
193
 
194
194
  # Returns a 3d NArray object where the array dimensions are related to [frames, columns, rows].
195
- # To call this method the user needs to have performed " require 'narray' " in advance.
195
+ # To call this method the user needs to have performed " require 'narray' " in advance.
196
196
  def get_image_narray
197
197
  # Does pixel data exist at all in the DICOM object?
198
198
  if @compression == nil
@@ -256,48 +256,46 @@ module DICOM
256
256
  end # of get_image_narray
257
257
 
258
258
 
259
- # Returns an array of RMagick image objects, where the size of the array corresponds with the number of frames in the image data.
260
- # To call this method the user needs to have performed " require 'RMagick' " in advance.
259
+ # Returns an array of RMagick image objects, where the size of the array corresponds to the number of frames in the image data.
260
+ # To call this method the user needs to have loaded the ImageMagick library in advance (require 'RMagick').
261
261
  def get_image_magick
262
262
  # Does pixel data exist at all in the DICOM object?
263
263
  if @compression == nil
264
- add_msg("It seems pixel data is not present in this DICOM object: returning false.")
264
+ add_msg("It seems pixel data is not present in this DICOM object: Returning false.")
265
265
  return false
266
266
  end
267
267
  # No support yet for color pixel data:
268
268
  if @color
269
- add_msg("Warning: Unpacking color pixel data is not supported yet for this method: aborting.")
269
+ add_msg("Warning: Unpacking color pixel data is not supported yet for this method: Aborting.")
270
270
  return false
271
271
  end
272
272
  # Gather information about the dimensions of the image data:
273
- rows = get_value("0028,0010")
274
- columns = get_value("0028,0011")
273
+ rows = get_value("0028,0010", :array => true)
274
+ columns = get_value("0028,0011", :array => true)
275
+ rows = [rows] unless rows.is_a?(Array)
276
+ columns = [columns] unless columns.is_a?(Array)
275
277
  frames = get_frames
276
278
  image_pos = get_image_pos
277
279
  # Array that will hold the RMagick image objects, one image object for each frame:
278
280
  image_arr = Array.new(frames)
281
+ # A hack for the special case (some MR files), where two images are stored (one is a smaller thumbnail image):
282
+ if image_pos.length > 1 and columns.length > 1
283
+ image_pos = [image_pos.last]
284
+ columns = [columns[0]]
285
+ rows = [rows[0]]
286
+ end
279
287
  # Handling of image data will depend on whether we have one or more frames,
280
288
  if image_pos.size == 1
281
- # All of the image data is located in one element:
282
- #image_data = get_image_data(image_pos[0])
283
- #(0..frames-1).each do |i|
284
- # image = Magick::Image.new(columns,rows)
285
- # image.import_pixels(0, 0, columns, rows, "I", image_data)
286
- # image_arr[i] = image
287
- #end
289
+ # All of the image data is located in one data element:
288
290
  if frames > 1
289
291
  add_msg("Unfortunately, this method only supports reading the first image frame as of now.")
290
292
  end
291
- image = read_image_magick(image_pos[0], columns, rows)
293
+ image = read_image_magick(image_pos[0], columns[0], rows[0])
292
294
  image_arr[0] = image
293
- #image_arr[i] = image
294
295
  else
295
296
  # Image data is encapsulated in items:
296
297
  (0..frames-1).each do |i|
297
- #image_data=get_image_data(image_pos[i])
298
- #image = Magick::Image.new(columns,rows)
299
- #image.import_pixels(0, 0, columns, rows, "I", image_data)
300
- image = read_image_magick(image_pos[i], columns, rows)
298
+ image = read_image_magick(image_pos[i], columns[0], rows[0])
301
299
  image_arr[i] = image
302
300
  end
303
301
  end
@@ -307,11 +305,9 @@ module DICOM
307
305
 
308
306
  # Returns the number of frames present in the image data in the DICOM file.
309
307
  def get_frames
310
- frames = get_value("0028,0008")
311
- if frames == false
312
- # If the DICOM object does not specify the number of frames explicitly, assume 1 image frame.
313
- frames = 1
314
- end
308
+ frames = get_value("0028,0008", :silent => true)
309
+ # If the DICOM object does not specify the number of frames explicitly, assume 1 image frame:
310
+ frames = 1 unless frames
315
311
  return frames.to_i
316
312
  end
317
313
 
@@ -320,10 +316,11 @@ module DICOM
320
316
  def get_pixels(pos)
321
317
  pixels = false
322
318
  # We need to know what kind of bith depth the pixel data is saved with:
323
- bit_depth = get_value("0028,0100")
324
- if bit_depth != false
319
+ bit_depth = get_value("0028,0100", :array => true)
320
+ unless bit_depth == false
325
321
  # Load the binary pixel data to the Stream instance:
326
322
  @stream.set_string(get_raw(pos))
323
+ bit_depth = bit_depth.first if bit_depth.is_a?(Array)
327
324
  # Number of bytes used per pixel will determine how to unpack this:
328
325
  case bit_depth
329
326
  when 8
@@ -774,7 +771,8 @@ module DICOM
774
771
  compression = "No"
775
772
  end
776
773
  # Bits per pixel (allocated):
777
- bits = get_value("0028,0100").to_s
774
+ bits = get_value("0028,0100", :array => true)
775
+ bits = bits[0].to_s if bits
778
776
  # Print the file properties:
779
777
  puts "Key properties of DICOM object:"
780
778
  puts "-------------------------------"
@@ -890,7 +888,7 @@ module DICOM
890
888
  add_msg("Warning: Method set_value could not create data element, either because data element name was not recognized in the library, or data element tag is invalid (Expected format of tags is 'GGGG,EEEE').")
891
889
  else
892
890
  # As we wish to create a new data element, we need to find out where to insert it in the element arrays:
893
- # We will do this by finding the last array position of the last element that will (alphabetically/numerically) stay in front of this element.
891
+ # We will do this by finding the array position of the last element that will (alphabetically/numerically) stay in front of this element.
894
892
  if @tags.size > 0
895
893
  # Search the array:
896
894
  index = -1
@@ -898,7 +896,7 @@ module DICOM
898
896
  while quit != true do
899
897
  if index+1 >= @tags.length # We have reached end of array.
900
898
  quit = true
901
- elsif tag < @tags[index+1] # We are past the correct position.
899
+ elsif tag < @tags[index+1] and @levels[index+1] == 0 # We are past the correct position (only match against top level tags).
902
900
  quit = true
903
901
  else # Increase index in anticipation of a 'hit'.
904
902
  index += 1
@@ -1005,19 +1003,21 @@ module DICOM
1005
1003
  end # of create_element
1006
1004
 
1007
1005
 
1008
- # Encodes a value to binary (used for inserting values to a DICOM object).
1006
+ # Encodes a value to binary (used for inserting values into a DICOM object).
1009
1007
  def encode(value, vr)
1010
- # Our value needs to be inside an array to be encoded:
1011
- value = [value] if not value.is_a?(Array)
1012
1008
  # VR will decide how to encode this value:
1013
1009
  case vr
1014
1010
  when "AT" # (Data element tag: Assume it has the format "GGGG,EEEE"
1015
- bin = @stream.encode_tag(value)
1011
+ if value.is_a_tag?
1012
+ bin = @stream.encode_tag(value)
1013
+ else
1014
+ add_msg("Invalid tag format (#{value}). Expected format: 'GGGG,EEEE'")
1015
+ end
1016
1016
  # We have a number of VRs that are encoded as string:
1017
1017
  when 'AE','AS','CS','DA','DS','DT','IS','LO','LT','PN','SH','ST','TM','UI','UT'
1018
1018
  # In case we are dealing with a number string element, the supplied value might be a number
1019
1019
  # instead of a string, and as such, we convert to string just to make sure this will work nicely:
1020
- value[0] = value[0].to_s
1020
+ value = value.to_s
1021
1021
  bin = @stream.encode_value(value, "STR")
1022
1022
  # Image related value representations:
1023
1023
  when "OW"
@@ -1049,6 +1049,7 @@ module DICOM
1049
1049
  return bin
1050
1050
  end # of encode
1051
1051
 
1052
+
1052
1053
  # Modifies existing data element:
1053
1054
  def modify_element(value, pos, options={})
1054
1055
  bin_only = options[:bin]
data/lib/DRead.rb CHANGED
File without changes
data/lib/DServer.rb CHANGED
File without changes
data/lib/DWrite.rb CHANGED
@@ -10,7 +10,8 @@
10
10
  # Please contact the author if you discover any issues with file creation.
11
11
 
12
12
  module DICOM
13
- # Class for writing the data from DObject to a valid DICOM file:
13
+
14
+ # Class for writing the data from a DObject to a valid DICOM file.
14
15
  class DWrite
15
16
 
16
17
  attr_writer :tags, :types, :lengths, :raw, :rest_endian, :rest_explicit
@@ -309,7 +310,8 @@ module DICOM
309
310
  end
310
311
 
311
312
 
312
- # Tests if the file is writable and opens it.
313
+ # Tests if the file/path is writable, creates any folders
314
+ # if necessary, and opens the file for writing.
313
315
  def open_file(file)
314
316
  # Two cases: File already exists or it does not.
315
317
  # Check if file exists:
@@ -323,22 +325,20 @@ module DICOM
323
325
  end
324
326
  else
325
327
  # File does not exist.
326
- # Check if this file's path contains a directory that does not exist and so need to be created:
327
- arr = file.split('/')
328
- if arr != nil
328
+ # Check if this file's path contains a folder that does not exist, and therefore needs to be created:
329
+ folders = file.split(File::SEPARATOR)
330
+ if folders.length > 1
329
331
  # Remove last element (which should be the file string):
330
- arr.pop
331
- if arr != nil
332
- path = arr.join('/')
333
- # Check if this path exists:
334
- if not File.directory?(path)
335
- # Need to create this path:
336
- require 'fileutils'
337
- FileUtils.mkdir_p path
338
- end
332
+ folders.pop
333
+ path = folders.join(File::SEPARATOR)
334
+ # Check if this path exists:
335
+ unless File.directory?(path)
336
+ # We need to create (parts of) this path:
337
+ require 'fileutils'
338
+ FileUtils.mkdir_p path
339
339
  end
340
340
  end
341
- # The path to this non-existing file should now be prepared, and we will thus create the file:
341
+ # The path to this non-existing file should now be prepared, and we proceed to creating the file:
342
342
  @file = File.new(file, "wb")
343
343
  end
344
344
  end
data/lib/Link.rb CHANGED
File without changes
data/lib/Stream.rb CHANGED
@@ -96,14 +96,16 @@ module DICOM
96
96
 
97
97
  # Encodes content (string, number, array of numbers) and returns the binary string.
98
98
  def encode(value, type)
99
- bin = [value].pack(vr_to_str(type))
99
+ value = [value] unless value.is_a?(Array)
100
+ return value.pack(vr_to_str(type))
100
101
  end
101
102
 
102
103
 
103
104
  # Encodes content (string, number, array of numbers) to a binary string and pastes it to
104
105
  # the beginning of the @string variable of this instance.
105
106
  def encode_first(value, type)
106
- bin = [value].pack(vr_to_str(type))
107
+ value = [value] unless value.is_a?(Array)
108
+ bin = value.pack(vr_to_str(type))
107
109
  @string = bin + @string
108
110
  end
109
111
 
@@ -111,7 +113,8 @@ module DICOM
111
113
  # Encodes content (string, number, array of numbers) to a binary string and pastes it to
112
114
  # the end of the @string variable of this instance.
113
115
  def encode_last(value, type)
114
- bin = [value].pack(vr_to_str(type))
116
+ value = [value] unless value.is_a?(Array)
117
+ bin = value.pack(vr_to_str(type))
115
118
  @string = @string + bin
116
119
  end
117
120
 
data/lib/dicom.rb CHANGED
File without changes
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dicom
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.6"
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christoffer Lervag
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-13 00:00:00 +02:00
12
+ date: 2009-08-23 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -65,6 +65,6 @@ rubyforge_project: dicom
65
65
  rubygems_version: 1.3.3
66
66
  signing_key:
67
67
  specification_version: 3
68
- summary: Library for handling DICOM files and network communication.
68
+ summary: Library for handling DICOM files and DICOM network communication.
69
69
  test_files: []
70
70