vil_dicom.cxx
Go to the documentation of this file.
1 // This is core/vil/file_formats/vil_dicom.cxx
2 //:
3 // \file
4 
5 #include <iostream>
6 #include <sstream>
7 #include <cstring>
8 #include <cstdlib>
9 #include <vector>
10 #include <vil/vil_config.h>
11 #if HAS_DCMTK
12 
13 #include "vil_dicom.h"
14 
15 #include <cassert>
16 #ifdef _MSC_VER
17 # include <vcl_msvc_warnings.h>
18 #endif
19 
20 #include <vxl_config.h> // for vxl_byte and such
21 
22 #include <vil/vil_property.h>
23 #include <vil/vil_stream.h>
24 #include <vil/vil_image_resource.h>
25 #include <vil/vil_new.h>
26 #include <vil/vil_image_view.h>
27 #include <vil/vil_pixel_format.h>
28 #include <vil/vil_exception.h>
29 
30 #include <dcmtk/dcmdata/dcfilefo.h>
31 #include <dcmtk/dcmdata/dcmetinf.h>
32 #include <dcmtk/dcmdata/dcdatset.h>
33 #include <dcmtk/dcmdata/dctagkey.h>
34 #include <dcmtk/dcmdata/dcdeftag.h>
35 #include <dcmtk/dcmdata/dcstack.h>
36 #include <dcmtk/dcmimgle/diinpxt.h>
37 
38 #include "vil_dicom_stream.h"
39 //
40 //Believe it or not some dicom images have a mixed endian encoding.
41 // e.g. mixed (7fe0,0010) OW 30f8 vs unmixed (7fe0,0010) OW f830
42 //The header is little endian and the data is big endian!! There doesn't
43 //seem to be a way of telling that this is the case. The DCM library
44 //reports that the TransferSyntax is "LittleEndianImplicit", which isn't helpful.
45 // This is a hack to be able to read such files
46 //#define MIXED_ENDIAN
47 // Another hack to remove the offset of -1024 needed to calibrate HU. Otherwise
48 // this reader converts the image to floating point, which may not be desired.
49 //#define NO_OFFSET
50 
51 char const* vil_dicom_format_tag = "dicom";
52 
53 
55 {
56  bool is_dicom = false;
57 
58  char magic[ DCM_MagicLen ];
59  vs->seek( DCM_PreambleLen );
60  if ( vs->read( magic, DCM_MagicLen ) == DCM_MagicLen ) {
61  if ( std::strncmp( magic, DCM_Magic, DCM_MagicLen ) == 0 ) {
62  is_dicom = true;
63  }
64  }
65 
66  if ( is_dicom )
67  return new vil_dicom_image( vs );
68  else
69  return 0;
70 }
71 
73  unsigned /*ni*/,
74  unsigned /*nj*/,
75  unsigned /*nplanes*/,
77 {
78  std::cerr << "ERROR: vil_dicom_file doesn't support output yet\n";
79  return 0;
80 #if 0
81 
82  if (nplanes != 1 || format != VIL_PIXEL_FORMAT_INT_32)
83  {
84  std::cerr << "ERROR: vil_dicom_file_format::make_output_image\n"
85  << " Can only create DICOM images with a single plane\n"
86  << " and 32-bit integer pixels\n";
87  return 0;
88  }
89  return new vil_dicom_image(vs, ni, nj, nplanes, format);
90 #endif
91 }
92 
93 char const* vil_dicom_file_format::tag() const
94 {
95  return vil_dicom_format_tag;
96 }
97 
98 
99 // ===========================================================================
100 // helper routines defined at end
101 
102 static
103 void
104 read_header( DcmObject* dataset, vil_dicom_header_info& i );
105 
106 static
107 void
108 read_pixels_into_buffer(DiDocument* doc,
109  unsigned num_samples,
110  unsigned nplanes,
111  Uint16 alloc,
112  Uint16 stored,
113  Uint16 high,
114  Uint16 rep,
115  Float64 slope,
116  Float64 intercept,
117  vil_memory_chunk_sptr& out_buf,
118  vil_pixel_format& out_format);
119 
121  : pixels_( 0 )
122 {
123  vil_dicom_header_info_clear( header_ );
124 
125  vil_dicom_stream_input dcis( vs );
126 
127  DcmFileFormat ffmt;
128  ffmt.transferInit();
129  OFCondition cond = ffmt.read( dcis );
130  ffmt.transferEnd();
131 
132  if ( cond != EC_Normal ) {
133  std::cerr << "vil_dicom ERROR: could not read file (" << cond.text() << ")\n"
134  << "And the error code is: " << cond.code() << std::endl;
135  //if (cond.code() != 4)
136  return;
137  }
138 
139  DcmDataset& dset = *ffmt.getDataset();
140  read_header( &dset, header_ );
141 
142  //correct known manufacturers' drop-offs in header data!
143  correct_manufacturer_discrepancies();
144 
145  // I don't know (yet) how to deal with look up tables. (Without the
146  // tables, the pixel values represent actual measurements.)
147  //
148  if ( dset.tagExists( DCM_ModalityLUTSequence ) ) {
149  std::cerr << "vil_dicom ERROR: don't know (yet) how to handle modality LUTs\n";
150  return;
151  }
152 
153  // If no ModalityLUT is present, I think the slope and intercept are
154  // required. However, it seems that some DICOM images don't, so
155  // assume the identity relationship.
156  //
157  Float64 slope, intercept;
158  if ( dset.findAndGetFloat64( DCM_RescaleSlope, slope ) != EC_Normal )
159  slope = 1;
160  if ( dset.findAndGetFloat64( DCM_RescaleIntercept, intercept ) != EC_Normal )
161  intercept = 0;
162 
163  // Gather the storage format info
164 
165 #define Stringify( v ) #v
166 #define MustRead( func, key, var ) \
167  do { \
168  if ( dset. func( key, var ) != EC_Normal ) { \
169  std::cerr << "vil_dicom ERROR: couldn't read " Stringify(key) "; can't handle\n"; \
170  return; \
171  }} while (false)
172 
173  Uint16 bits_alloc, bits_stored, high_bit, pixel_rep;
174 
175  MustRead( findAndGetUint16, DCM_BitsAllocated, bits_alloc );
176  MustRead( findAndGetUint16, DCM_BitsStored, bits_stored );
177  MustRead( findAndGetUint16, DCM_HighBit, high_bit );
178  MustRead( findAndGetUint16, DCM_PixelRepresentation, pixel_rep );
179 
180 #undef MustRead
181 #undef Stringify
182 
183  // The pixels buffer will eventually be assigned to pixel_buf, and
184  // the pixel format written into pixel_format.
185  //
186  vil_memory_chunk_sptr pixel_buf;
188 
189  // First, read in the bytes and interpret them appropriately
190  //
191  {
192  DcmPixelData* pixels = 0;
193  DcmStack stack;
194  if ( dset.search( DCM_PixelData, stack, ESM_fromHere, true ) == EC_Normal )
195  {
196  if ( stack.card() == 0 ) {
197  std::cerr << "vil_dicom ERROR: no pixel data found\n";
198  return;
199  }
200  else {
201  assert( stack.top()->ident() == EVR_PixelData );
202  }
203  }
204 
205  DiDocument doc(&dset, EXS_Unknown);
206  pixels = doc.getPixelData();
207 
208  unsigned num_samples = ni() * nj() * nplanes();
209  read_pixels_into_buffer(&doc, num_samples, nplanes(),
210  bits_alloc, bits_stored, high_bit, pixel_rep,
211  slope, intercept,
212  pixel_buf, pixel_format);
213  }
214 
215  // Create an image resource to manage the pixel buffer
216  //
217 #define DOCASE( fmt ) \
218  case fmt: { \
219  typedef vil_pixel_format_type_of<fmt>::component_type T; \
220  pixels_ = vil_new_image_resource_of_view( \
221  vil_image_view<T>(pixel_buf, \
222  (T*)pixel_buf->data(), \
223  ni(), nj(), nplanes(), \
224  nplanes(), ni()*nplanes(), 1));\
225  } break
226 
227  switch ( pixel_format ) {
228  DOCASE( VIL_PIXEL_FORMAT_UINT_16 );
229  DOCASE( VIL_PIXEL_FORMAT_INT_16 );
230  DOCASE( VIL_PIXEL_FORMAT_BYTE );
231  DOCASE( VIL_PIXEL_FORMAT_SBYTE );
232  DOCASE( VIL_PIXEL_FORMAT_FLOAT );
233  default: std::cerr << "vil_dicom ERROR: unexpected pixel format\n";
234  }
235 #undef DOCASE
236 }
237 
238 
239 bool vil_dicom_image::get_property(char const* tag, void* value) const
240 {
241  if (std::strcmp(vil_property_quantisation_depth, tag)==0)
242  {
243  if (value)
244  *static_cast<unsigned int*>(value) = header_.stored_bits_;
245  return true;
246  }
247 
248  if (std::strcmp(vil_property_pixel_size, tag)==0 && value!=0)
249  {
250  float *pixel_size = static_cast<float*>(value);
251  pixel_size[0] = header_.spacing_x_ / 1000.0f;
252  pixel_size[1] = header_.spacing_y_ / 1000.0f;
253  return true;
254  }
255 
256  // Need to write lots of access code for the dicom header.
257  return false;
258 }
259 
260 char const* vil_dicom_image::file_format() const
261 {
262  return vil_dicom_format_tag;
263 }
264 
265 vil_dicom_image::vil_dicom_image(vil_stream* /*vs*/, unsigned ni, unsigned nj,
266  unsigned nplanes, vil_pixel_format format)
267 {
268  assert(!"vil_dicom_image doesn't yet support output");
269 
270  assert(nplanes == 1 && format == VIL_PIXEL_FORMAT_INT_32);
271  header_.size_x_ = ni;
272  header_.size_y_ = nj;
273  header_.size_z_ = 1;
274 }
275 
277 {
278 }
279 
280 unsigned vil_dicom_image::nplanes() const
281 {
282  return header_.pix_samps_;
283 }
284 
285 unsigned vil_dicom_image::ni() const
286 {
287  return header_.size_x_;
288 }
289 
290 unsigned vil_dicom_image::nj() const
291 {
292  return header_.size_y_;
293 }
294 
296 {
297  return pixels_ ? pixels_->pixel_format() : VIL_PIXEL_FORMAT_UNKNOWN;
298 }
299 
301  unsigned x0, unsigned nx, unsigned y0, unsigned ny) const
302 {
303  return pixels_ ? pixels_->get_copy_view( x0, nx, y0, ny ) : 0;
304 }
305 
307  unsigned x0, unsigned nx, unsigned y0, unsigned ny) const
308 {
309  return pixels_ ? pixels_->get_view( x0, nx, y0, ny ) : 0;
310 }
311 
313  unsigned x0, unsigned y0)
314 {
315  assert(!"vil_dicom_image doesn't yet support output yet");
316 
317  if (!view_fits(view, x0, y0))
318  {
319  vil_exception_warning(vil_exception_out_of_bounds("vil_dicom_image::put_view"));
320  return false;
321  }
322 
323  return false;
324 }
325 
326 // ===========================================================================
327 //MANUFACTURER SPECIFIC TWEAKS
328 //--- Add any further manufacturer specific tweaks in this section,
329 // but if it all gets out of hand, then we will need some derived classes which should attempt to read first
330 // ===========================================================================
331 
332 //:correct known manufacturers drop-offs in header data!
333 //For example Hologic encode pixel-size in the imageComment!
334 //NB if this section starts bloating, use derived classes which override correct_manufacturer_discrepancies
336 {
337  //If manufacturer is Hologic and it's a QDR or Discovery model DXA scanner...
338  if ( ( (header_.manufacturer_ == "HOLOGIC") || (header_.manufacturer_ == "Hologic") ) &&
339  ( (header_.model_name_.find("QDR") != header_.model_name_.npos ) ||
340  (header_.model_name_.find("Discovery") != header_.model_name_.npos ) ) )
341  {
342  //Hologic QDR Bone Densitometry source - set (default) pixel spacing from private format image comments
343  float xPixelSize=1.0;
344  float yPixelSize=1.0;
345  if (interpret_hologic_header(xPixelSize,yPixelSize))
346  {
347  header_.spacing_x_ = xPixelSize;
348  header_.spacing_y_ = yPixelSize;
349  }
350  }
351 
352  //
353  // GE Lunar iDXA scanner produces files with no indication of the pixel size or scaling, other than the
354  // exposed area.
355  //
356  if ( ( (header_.manufacturer_ == "GE Healthcare") ) &&
357  ( (header_.model_name_.find("Lunar iDXA") != header_.model_name_.npos ) ) )
358  {
359  //GE Lunar iDXA scanner: set pixel size from exposed area and number of rows/columns
360 
362  {
367  }
368  }
369 
370  // By default, set the pixel spacing to 1 if it is still 0 after correcting for any discrepancies.
371  // This is, for example, the case if the pixel spacing has been explicitely set to 0 in the file header
372  // without any further manufacturer-specific information.
373  if ((header_.spacing_x_ == 0) && (header_.spacing_y_ == 0))
374  {
375  header_.spacing_x_ = 1;
376  header_.spacing_y_ = 1;
377  }
378 }
379 
380 //:try and interpret the Hologic comments section to extract pixel size
381 bool vil_dicom_image::interpret_hologic_header(float& xpixSize, float& ypixSize)
382 {
383  //The magic internal Hologic tags used within their vast "Image Comments"
384  //which is used as a cop-out from sensible DICOM conformance
385  static const std::string HOLOGIC_PixelXSizeMM = "<PixelXSizeMM>";
386  static const std::string HOLOGIC_PixelXSizeMM_END = "</PixelXSizeMM>";
387  static const std::string HOLOGIC_PixelYSizeMM = "<PixelYSizeMM>";
388  static const std::string HOLOGIC_PixelYSizeMM_END = "</PixelYSizeMM>";
389 
390  std::string src = header_.image_comments_;
391  //Find start of x pixel size sub-text
392  std::size_t ipxStart = src.find(HOLOGIC_PixelXSizeMM);
393  if (ipxStart==src.npos) return false;
394 
395  //Find end of x pixel size sub-text
396  std::size_t ipxEnd = src.find(HOLOGIC_PixelXSizeMM_END,ipxStart);
397  if (ipxEnd==src.npos) return false;
398 
399  //Extract just the numerical part of the text
400  std::string strPixelXSizeMM="";
401  ipxStart+= HOLOGIC_PixelXSizeMM.size();
402  strPixelXSizeMM.append(src,ipxStart, ipxEnd-ipxStart);
403 
404  if (strPixelXSizeMM.size()>0)
405  {
406  //Translate string to number
407  std::stringstream translate_is(strPixelXSizeMM,std::stringstream::in);
408  translate_is>>xpixSize;
409  if (!translate_is) return false;
410  if (xpixSize<=0.0 || xpixSize>=1.0E6)
411  return false; //Don't believe crazy values
412  }
413  else
414  {
415  return false; //No x pixel value present between the tags
416  }
417 
418  //Find start of y pixel size sub-text
419  std::size_t ipyStart = src.find(HOLOGIC_PixelYSizeMM);
420  if (ipyStart==src.npos) return false;
421 
422  //Find end of y pixel size sub-text
423  std::size_t ipyEnd = src.find(HOLOGIC_PixelYSizeMM_END,ipyStart);
424  if (ipyEnd==src.npos) return false;
425 
426  //Extract just the numerical part of the text
427  std::string strPixelYSizeMM="";
428  ipyStart+= HOLOGIC_PixelYSizeMM.size();
429  strPixelYSizeMM.append(src,ipyStart, ipyEnd-ipyStart);
430 
431  if (strPixelYSizeMM.size()>0)
432  {
433  //Translate string to number
434  std::stringstream translate_is(strPixelYSizeMM,std::stringstream::in);
435  translate_is>>ypixSize;
436  if (!translate_is) return false;
437  if (ypixSize<=0.0 || ypixSize>=1.0E6)
438  return false; //Don't believe crazy values
439  }
440  else
441  {
442  return false; //No y pixel value present between the tags
443  }
444 
445  return true; //It all worked
446 }
447 
448 
449 // ===========================================================================
450 // HELPER ROUTINES
451 // ===========================================================================
452 
453 
454 static
455 DcmElement*
456 find_element( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element )
457 {
458  DcmElement* result = 0;
459  DcmTagKey key( group, element );
460  DcmStack stack;
461  if ( dset->search( key, stack, ESM_fromHere, true ) == EC_Normal )
462  {
463  if ( stack.card() == 0 ) {
464  std::cerr << "vil_dicom ERROR: no results on stack\n";
465  }
466  else {
467  result = static_cast<DcmElement*>(stack.top());
468  if ( result->getVM() == 0 ) {
469  // header present, but has no value == header not present
470  result = 0;
471  }
472  }
473  }
474 
475  return result;
476 }
477 
478 // anonymous namespace for helper routines
479 namespace
480 {
481  // Specializations of this template contains code to convert from the
482  // given VR type (template parameter) to the given C++ type (4th
483  // parameter of the function "proc").
484  //
485  template <int T /*vil_dicom_header_vr_type*/>
486  struct try_set;
487 
488  // A general proc implementation that returns a string representation
489  // of any VR.
490  //
491  struct try_set_to_string
492  {
493  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, std::string& value ) {
494  DcmElement* e = find_element( dset, group, element );
495  if ( e )
496  {
497  OFString str;
498  if ( e->getOFString( str, 0 ) != EC_Normal ) {
499  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
500  }
501  else {
502  value = str.c_str();
503  }
504  }
505  }
506  };
507 
508  template <>
509  struct try_set< vil_dicom_header_AE >
510  : public try_set_to_string
511  {
512  };
513 
514  template <>
515  struct try_set< vil_dicom_header_AS >
516  : public try_set_to_string
517  {
518  };
519 
520  template <>
521  struct try_set< vil_dicom_header_AT >
522  : public try_set_to_string
523  {
524  };
525 
526  template <>
527  struct try_set< vil_dicom_header_CS >
528  : public try_set_to_string
529  {
530  };
531 
532  template <>
533  struct try_set< vil_dicom_header_DA >
534  {
535  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, long& value ) {
536  DcmElement* e = find_element( dset, group, element );
537  if ( e )
538  {
539  OFString str;
540  if ( e->getOFString( str, 0 ) != EC_Normal ) {
541  std::cerr << "Warning: value of ("<<group<<','<<element<<") is not string\n";
542  }
543  else {
544  value = std::atol( str.c_str() );
545  }
546  }
547  }
548  };
549 
550  template <>
551  struct try_set< vil_dicom_header_DS >
552  {
553  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, float& value ) {
554  DcmElement* e = find_element( dset, group, element );
555  if ( e )
556  {
557  OFString str;
558  if ( e->getOFString( str, 0 ) != EC_Normal ) {
559  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
560  }
561  else {
562  value = static_cast<float>( std::atof( str.c_str() ) );
563  }
564  }
565  }
566 
567  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, std::vector<float>& value ) {
568  DcmElement* e = find_element( dset, group, element );
569  if ( e ) {
570  for ( unsigned pos = 0; pos < e->getVM(); ++pos )
571  {
572  OFString str;
573  if ( e->getOFString( str, pos ) != EC_Normal ) {
574  std::cerr << "Warning: value of ("<<group<<','<<element<<") at " << pos << " is not string\n";
575  }
576  else {
577  value.push_back( static_cast<float>( std::atof( str.c_str() ) ) );
578  }
579  }
580  }
581  }
582  };
583 
584  template <>
585  struct try_set< vil_dicom_header_FD >
586  {
587  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_ieee_64& value ) {
588  DcmElement* e = find_element( dset, group, element );
589  if ( e ) {
590  if ( e->getFloat64( value ) != EC_Normal ) {
591  std::cerr << "Warning: value of ("<<group<<','<<element<<") is not Float64\n";
592  }
593  }
594  }
595  };
596 
597  template <>
598  struct try_set< vil_dicom_header_FL >
599  {
600  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_ieee_32& value ) {
601  DcmElement* e = find_element( dset, group, element );
602  if ( e ) {
603  if ( e->getFloat32( value ) != EC_Normal ) {
604  std::cerr << "Warning: value of ("<<group<<','<<element<<") is not Float32\n";
605  }
606  }
607  }
608  };
609 
610  template <>
611  struct try_set< vil_dicom_header_IS >
612  {
613  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, long& value ) {
614  DcmElement* e = find_element( dset, group, element );
615  if ( e )
616  {
617  OFString str;
618  if ( e->getOFString( str, 0 ) != EC_Normal ) {
619  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
620  }
621  else {
622  value = std::atol( str.c_str() );
623  }
624  }
625  }
626  };
627 
628  template <>
629  struct try_set< vil_dicom_header_LO >
630  : public try_set_to_string
631  {
632  };
633 
634  template <>
635  struct try_set< vil_dicom_header_LT >
636  : public try_set_to_string
637  {
638  };
639 
640  template <>
641  struct try_set< vil_dicom_header_OB >
642  : public try_set_to_string
643  {
644  };
645 
646  template <>
647  struct try_set< vil_dicom_header_OW >
648  : public try_set_to_string
649  {
650  };
651 
652  template <>
653  struct try_set< vil_dicom_header_PN >
654  : public try_set_to_string
655  {
656  };
657 
658  template <>
659  struct try_set< vil_dicom_header_SH >
660  : public try_set_to_string
661  {
662  };
663 
664  template <>
665  struct try_set< vil_dicom_header_SL >
666  {
667  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_sint_32& value ) {
668  DcmElement* e = find_element( dset, group, element );
669  if ( e ) {
670  if ( e->getSint32( reinterpret_cast<Sint32&>(value) ) != EC_Normal ) {
671  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Sint32\n";
672  }
673  }
674  }
675  };
676 
677  template <>
678  struct try_set< vil_dicom_header_SQ >
679  : public try_set_to_string
680  {
681  };
682 
683  template <>
684  struct try_set< vil_dicom_header_SS >
685  {
686  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_sint_16& value ) {
687  DcmElement* e = find_element( dset, group, element );
688  if ( e ) {
689  if ( e->getSint16( reinterpret_cast<Sint16&>(value) ) != EC_Normal ) {
690  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Sint16\n";
691  }
692  }
693  }
694  };
695 
696  template <>
697  struct try_set< vil_dicom_header_ST >
698  : public try_set_to_string
699  {
700  };
701 
702  template <>
703  struct try_set< vil_dicom_header_TM >
704  {
705  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, float& value ) {
706  DcmElement* e = find_element( dset, group, element );
707  if ( e )
708  {
709  OFString str;
710  if ( e->getOFString( str, 0 ) != EC_Normal ) {
711  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
712  }
713  else {
714  value = static_cast<float>( std::atof( str.c_str() ) );
715  }
716  }
717  }
718  };
719 
720  template <>
721  struct try_set< vil_dicom_header_UI >
722  : public try_set_to_string
723  {
724  };
725 
726  template <>
727  struct try_set< vil_dicom_header_UL >
728  {
729  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_uint_32& value ) {
730  DcmElement* e = find_element( dset, group, element );
731  if ( e ) {
732  if ( e->getUint32( reinterpret_cast<Uint32&>(value) ) != EC_Normal ) {
733  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Uint32\n";
734  }
735  }
736  }
737  };
738 
739  template <>
740  struct try_set< vil_dicom_header_UN >
741  : public try_set_to_string
742  {
743  };
744 
745  template <>
746  struct try_set< vil_dicom_header_US >
747  {
748  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_uint_16& value ) {
749  DcmElement* e = find_element( dset, group, element );
750  if ( e ) {
751  if ( e->getUint16( value ) != EC_Normal ) {
752  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Uint16\n";
753  }
754  }
755  }
756 
757  static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, std::vector<vxl_uint_16>& value ) {
758  DcmElement* e = find_element( dset, group, element );
759  if ( e ) {
760  vxl_uint_16 value_at_pos;
761  for ( unsigned long pos = 0; pos < e->getVM(); ++pos )
762  {
763  if ( e->getUint16( value_at_pos, pos ) != EC_Normal ) {
764  std::cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") at " << pos << " is not Uint16\n";
765  }
766  else {
767  value.push_back(value_at_pos);
768  }
769  }
770  }
771  }
772  };
773 
774  template <>
775  struct try_set< vil_dicom_header_UT >
776  : public try_set_to_string
777  {
778  };
779 } // end anonymous namespace
780 
781 static
782 void
783 read_header( DcmObject* f, vil_dicom_header_info& i )
784 {
785  vxl_uint_16 group;
786 
787 #define ap_join(A,B) A ## B
788 #define ap_type(X) ap_join( vil_dicom_header_, X )
789 #define ap_el(X) ap_join( VIL_DICOM_HEADER_, X )
790 
792  try_set< ap_type(CS) >::proc( f, group, ap_el(IDIMAGETYPE), i.image_id_type_ ); // It's the image type
793  try_set< ap_type(UI) >::proc( f, group, ap_el(IDSOPCLASSID), i.sop_cl_uid_ ); // It's the SOP class ID
794  try_set< ap_type(UI) >::proc( f, group, ap_el(IDSOPINSTANCEID), i.sop_in_uid_ ); // It's the SOP instance ID
795  try_set< ap_type(DA) >::proc( f, group, ap_el(IDSTUDYDATE), i.study_date_ ); // It's the study date
796  try_set< ap_type(DA) >::proc( f, group, ap_el(IDSERIESDATE), i.series_date_ ); // It's the series date
797  try_set< ap_type(DA) >::proc( f, group, ap_el(IDACQUISITIONDATE), i.acquisition_date_ ); // It's the acquisition date
798  try_set< ap_type(DA) >::proc( f, group, ap_el(IDIMAGEDATE), i.image_date_ ); // It's the image date
799  try_set< ap_type(TM) >::proc( f, group, ap_el(IDSTUDYTIME), i.study_time_ ); // It's the study time
800  try_set< ap_type(TM) >::proc( f, group, ap_el(IDSERIESTIME), i.series_time_ ); // It's the series time
801  try_set< ap_type(TM) >::proc( f, group, ap_el(IDACQUISITIONTIME), i.acquisition_time_ ); // It's the acquisition time
802  try_set< ap_type(TM) >::proc( f, group, ap_el(IDIMAGETIME), i.image_time_ ); // It's the image time
803  try_set< ap_type(SH) >::proc( f, group, ap_el(IDACCESSIONNUMBER), i.accession_number_ ); // It's the accession number
804  try_set< ap_type(CS) >::proc( f, group, ap_el(IDMODALITY), i.modality_ ); // It's the imaging modality
805  try_set< ap_type(LO) >::proc( f, group, ap_el(IDMANUFACTURER), i.manufacturer_ ); // It's the manufacturer name
806  try_set< ap_type(LO) >::proc( f, group, ap_el(IDINSTITUTIONNAME), i.institution_name_ ); // It's the institution name
807  try_set< ap_type(ST) >::proc( f, group, ap_el(IDINSTITUTIONADDRESS),i.institution_addr_ ); // It's the institution address
808  try_set< ap_type(PN) >::proc( f, group, ap_el(IDREFERRINGPHYSICIAN),i.ref_phys_name_ ); // It's the referring physician's name
809  try_set< ap_type(SH) >::proc( f, group, ap_el(IDSTATIONNAME), i.station_name_ ); // It's the imaging station name
810  try_set< ap_type(LO) >::proc( f, group, ap_el(IDSTUDYDESCRIPTION), i.study_desc_ ); // It's the study description
811  try_set< ap_type(LO) >::proc( f, group, ap_el(IDSERIESDESCRIPTION), i.series_desc_ ); // It's the series description
812  try_set< ap_type(PN) >::proc( f, group, ap_el(IDATTENDINGPHYSICIAN),i.att_phys_name_); // It's the name of the attending physician
813  try_set< ap_type(PN) >::proc( f, group, ap_el(IDOPERATORNAME), i.operator_name_ ); // It's the name of the scanner operator
814  try_set< ap_type(LO) >::proc( f, group, ap_el(IDMANUFACTURERMODEL), i.model_name_ ); // It's the scanner model
815 
817  try_set< ap_type(PN) >::proc( f, group, ap_el(PIPATIENTNAME), i.patient_name_ ); // It's the patient's name
818  try_set< ap_type(LO) >::proc( f, group, ap_el(PIPATIENTID), i.patient_id_ ); // It's the patient's id
819  try_set< ap_type(DA) >::proc( f, group, ap_el(PIPATIENTBIRTHDATE),i.patient_dob_ ); // It's the patient's date of birth
820  try_set< ap_type(CS) >::proc( f, group, ap_el(PIPATIENTSEX), i.patient_sex_ ); // It's the patient's sex
821  try_set< ap_type(AS) >::proc( f, group, ap_el(PIPATIENTAGE), i.patient_age_ ); // It's the patient's age
822  try_set< ap_type(DS) >::proc( f, group, ap_el(PIPATIENTWEIGHT), i.patient_weight_ ); // It's the patient's weight
823  try_set< ap_type(LT) >::proc( f, group, ap_el(PIPATIENTHISTORY), i.patient_hist_ ); // It's the patient's history
824 
826  try_set< ap_type(CS) >::proc( f, group, ap_el(AQSCANNINGSEQUENCE), i.scanning_seq_ ); // It's the scanning sequence
827  try_set< ap_type(CS) >::proc( f, group, ap_el(AQSEQUENCEVARIANT), i.sequence_var_ ); // It's the sequence variant
828  try_set< ap_type(CS) >::proc( f, group, ap_el(AQSCANOPTIONS), i.scan_options_ ); // It's the scan options
829  try_set< ap_type(CS) >::proc( f, group, ap_el(AQMRACQUISITIONTYPE), i.mr_acq_type_ ); // It's the MR acquisition type
830  try_set< ap_type(SH) >::proc( f, group, ap_el(AQSEQUENCENAME), i.sequence_name_ ); // It's the sequence name
831  try_set< ap_type(CS) >::proc( f, group, ap_el(AQANGIOFLAG), i.angio_flag_ ); // It's the angio flag
832  try_set< ap_type(DS) >::proc( f, group, ap_el(AQSLICETHICKNESS), i.slice_thickness_ ); // It's the slice thickness
833  try_set< ap_type(DS) >::proc( f, group, ap_el(AQREPETITIONTIME), i.repetition_time_ ); // It's the repetition time
834  try_set< ap_type(DS) >::proc( f, group, ap_el(AQECHOTIME), i.echo_time_ ); // It's the echo time
835  try_set< ap_type(DS) >::proc( f, group, ap_el(AQINVERSIONTIME), i.inversion_time_ ); // It's the inversion time
836  try_set< ap_type(DS) >::proc( f, group, ap_el(AQNUMBEROFAVERAGES), i.number_of_averages_ ); // It's the number of averages
837  try_set< ap_type(IS) >::proc( f, group, ap_el(AQECHONUMBERS), i.echo_numbers_ ); // It's the echo numbers
838  try_set< ap_type(DS) >::proc( f, group, ap_el(AQMAGNETICFIELDSTRENGTH), i.mag_field_strength_);// It's the magnetic field strength
839  try_set< ap_type(DS) >::proc( f, group, ap_el(AQSLICESPACING), i.spacing_slice_ ); // It's the slice spacing
840  try_set< ap_type(IS) >::proc( f, group, ap_el(AQECHOTRAINLENGTH), i.echo_train_length_ ); // It's the echo train length
841  try_set< ap_type(DS) >::proc( f, group, ap_el(AQPIXELBANDWIDTH), i.pixel_bandwidth_ ); // It's the pixel bandwidth
842  try_set< ap_type(LO) >::proc( f, group, ap_el(AQSOFTWAREVERSION), i.software_vers_ ); // It's the scanner software version
843  try_set< ap_type(LO) >::proc( f, group, ap_el(AQPROTOCOLNAME), i.protocol_name_ ); // It's the protocol name
844  try_set< ap_type(DS) >::proc( f, group, ap_el(AQTRIGGERTIME), i.trigger_time_ ); // It's the trigger time
845  try_set< ap_type(IS) >::proc( f, group, ap_el(AQHEARTRATE), i.heart_rate_ ); // It's the heart rate
846  try_set< ap_type(IS) >::proc( f, group, ap_el(AQCARDIACNUMBEROFIMAGES), i.card_num_images_ ); // It's the cardiac number of images
847  try_set< ap_type(IS) >::proc( f, group, ap_el(AQTRIGGERWINDOW), i.trigger_window_ ); // It's the trigger window
848  try_set< ap_type(DS) >::proc( f, group, ap_el(AQRECONTRUCTIONDIAMETER), i.reconst_diameter_ ); // It's the reconstruction diameter
849  try_set< ap_type(SH) >::proc( f, group, ap_el(AQRECEIVINGCOIL), i.receiving_coil_ ); // It's the receiving coil
850  try_set< ap_type(CS) >::proc( f, group, ap_el(AQPHASEENCODINGDIRECTION),i.phase_enc_dir_ ); // It's the phase encoding direction
851  try_set< ap_type(DS) >::proc( f, group, ap_el(AQFLIPANGLE), i.flip_angle_ ); // It's the flip angle
852  try_set< ap_type(DS) >::proc( f, group, ap_el(AQSAR), i.sar_ ); // It's the sar
853  try_set< ap_type(CS) >::proc( f, group, ap_el(AQPATIENTPOSITION), i.patient_pos_ ); // It's the patient position
854 
856  std::vector<DS_type> ps_ips;
857  try_set< ap_type(DS) >::proc( f, group, ap_el(AQIMAGERPIXELSPACING), ps_ips );
858  if ( ps_ips.size() > 0 )
859  i.imager_spacing_x_ = ps_ips[0];
860  else
861  i.imager_spacing_x_ = 0;
862  if ( ps_ips.size() > 1 )
863  i.imager_spacing_y_ = ps_ips[1];
864  else
866 
868  try_set< ap_type(UI) >::proc( f, group, ap_el(RSSTUDYINSTANCEUID), i.stud_ins_uid_ ); // It's the study instance id
869  try_set< ap_type(UI) >::proc( f, group, ap_el(RSSERIESINSTANCEUID), i.ser_ins_uid_ ); // It's the series instance id
870  try_set< ap_type(SH) >::proc( f, group, ap_el(RSSTUDYID), i.study_id_ ); // It's the study id
871  try_set< ap_type(IS) >::proc( f, group, ap_el(RSSERIESNUMBER), i.series_number_ ); // It's the series number
872  try_set< ap_type(IS) >::proc( f, group, ap_el(RSAQUISITIONNUMBER), i.acquisition_number_ ); // It's the acqusition number
873  try_set< ap_type(IS) >::proc( f, group, ap_el(RSIMAGENUMBER), i.image_number_ ); // It's the image number
874  try_set< ap_type(CS) >::proc( f, group, ap_el(RSPATIENTORIENTATION), i.pat_orient_ ); // It's the patient orientation
875  try_set< ap_type(DS) >::proc( f, group, ap_el(RSIMAGEPOSITION), i.image_pos_ ); // It's the image position
876  try_set< ap_type(DS) >::proc( f, group, ap_el(RSIMAGEORIENTATION), i.image_orient_ ); // It's the image orientation
877  try_set< ap_type(UI) >::proc( f, group, ap_el(RSFRAMEOFREFERENCEUID),i.frame_of_ref_ ); // It's the frame of reference uid
878  try_set< ap_type(IS) >::proc( f, group, ap_el(RSIMAGESINACQUISITION),i.images_in_acq_); // the number of images in the acquisition
879  try_set< ap_type(LO) >::proc( f, group, ap_el(RSPOSITIONREFERENCE), i.pos_ref_ind_ ); // It's the position reference
880  try_set< ap_type(LT) >::proc( f, group, ap_el(RSIMAGECOMMENTS), i.image_comments_ ); // It's the image comments
881 
883  try_set< ap_type(US) >::proc( f, group, ap_el(IMSAMPLESPERPIXEL), i.pix_samps_ ); // It's the samples per pixel
884  try_set< ap_type(CS) >::proc( f, group, ap_el(IMPHOTOMETRICINTERP), i.photo_interp_ ); // It's the photometric interpretation
885  try_set< ap_type(US) >::proc( f, group, ap_el(IMROWS), i.size_y_ ); // It's the rows
886  try_set< ap_type(US) >::proc( f, group, ap_el(IMCOLUMNS), i.size_x_ ); // It's the columns
887  try_set< ap_type(US) >::proc( f, group, ap_el(IMPLANES), i.size_z_ ); // It's the planes
888  try_set< ap_type(US) >::proc( f, group, ap_el(IMBITSALLOCATED), i.allocated_bits_ ); // It's the allocated bits
889  try_set< ap_type(US) >::proc( f, group, ap_el(IMBITSSTORED), i.stored_bits_ ); // It's the stored bits info
890  try_set< ap_type(US) >::proc( f, group, ap_el(IMHIGHBIT), i.high_bit_ ); // It's the high bit
891  try_set< ap_type(US) >::proc( f, group, ap_el(IMPIXELREPRESENTATION),i.pix_rep_ ); // It's the pixel representation
892  try_set< ap_type(US) >::proc( f, group, ap_el(IMSMALLIMPIXELVALUE), i.small_im_pix_val_ ); // It's the smallest image pixel value
893  try_set< ap_type(US) >::proc( f, group, ap_el(IMLARGEIMPIXELVALUE), i.large_im_pix_val_ ); // It's the largest image pixel value
894  try_set< ap_type(US) >::proc( f, group, ap_el(IMPIXELPADDINGVALUE), i.pixel_padding_val_ ); // It's the pixel padding value
895  try_set< ap_type(DS) >::proc( f, group, ap_el(IMWINDOWCENTER), i.window_centre_ ); // It's the window centre
896  try_set< ap_type(DS) >::proc( f, group, ap_el(IMWINDOWWIDTH), i.window_width_ ); // It's the window width
897  try_set< ap_type(DS) >::proc( f, group, ap_el(IMRESCALEINTERCEPT), i.res_intercept_ ); // It's the rescale intercept
898  try_set< ap_type(DS) >::proc( f, group, ap_el(IMRESCALESLOPE), i.res_slope_ ); // It's the rescale slope
899 
900  std::vector<DS_type> ps;
901  try_set< ap_type(DS) >::proc( f, group, ap_el(IMPIXELSPACING), ps );
902  if ( ps.size() > 0 )
903  i.spacing_x_ = ps[0];
904  else
905  i.spacing_x_ = 0;
906  if ( ps.size() > 1 )
907  i.spacing_y_ = ps[1];
908  else
909  i.spacing_y_ = i.spacing_x_;
910  // check whether pixelspacing is available if not set to imagerpixelspacing
911  // Note: I removed the messages here since they may not be accurate; correct_manufacturer_discrepancies
912  // obtains accurate pixel spacings for some images.
913 
914  if (ps.size() <= 0)
915  {
916  if (ps_ips.size() <= 0)
917  {
918  i.spacing_x_ = 1;
919  i.spacing_y_ = 1;
920  //std::cout<<"DICOM tags PixelSpacing and ImagerPixelSpacing missing: use PixelSpacing = 1.0."<<std::endl;
921  }
922  else if (ps_ips.size() > 1)
923  {
926  //std::cout<<"DICOM tag PixelSpacing missing: use PixelSpacing = ImagerPixelSpacing."<<std::endl;
927  }
928  else if (ps_ips.size() > 0)
929  {
932  //std::cout<<"DICOM tag x.PixelSpacing missing: use x.PixelSpacing = x.ImagerPixelSpacing."<<std::endl;
933  //std::cout<<"DICOM tags y.PixelSpacing and y.ImagerPixelSpacing missing: use y.PixelSpacing = x.ImagerPixelSpacing."<<std::endl;
934  }
935  }
936 
938  try_set< ap_type(FD) >::proc( f, group, ap_el(PRREALWORLDVALUEINTERCEPT),i.real_world_value_intercept_ ); // It's the real world intercept value
939  try_set< ap_type(FD) >::proc( f, group, ap_el(PRREALWORLDVALUESLOPE), i.real_world_value_slope_ ); // It's the real world slope value
940 
942  std::vector<US_type> psb;
943  try_set< ap_type(US) >::proc( f, group, ap_el(EXPOSEDAREA), psb );
944  if ( psb.size() > 0 )
945  i.exposedarea_x_ = psb[0];
946  else
947  i.exposedarea_x_ = 0;
948  if ( psb.size() > 1 )
949  i.exposedarea_y_ = psb[1];
950  else
952 
954  try_set< ap_type(DS) >::proc( f, group, ap_el(NSPHILIPSPRIVATEINTERCEPT),i.philips_private_intercept_); // It's the Philips private intercept value
955  try_set< ap_type(DS) >::proc( f, group, ap_el(NSPHILIPSPRIVATESLOPE), i.philips_private_slope_); // It's the Philips private slope value
956 
957  i.header_valid_ = true;
958 
959 #undef ap_join
960 #undef ap_type
961 #undef ap_el
962 }
963 
964 
965 // start anonymous namespace for helpers
966 namespace
967 {
968  template<class InT>
969  void
970  convert_src_type(InT const *,
971  DiDocument *document,
972  unsigned num_samples,
973  unsigned nplanes,
974  Uint16 alloc,
975  Uint16 stored,
976  Uint16 high,
977  Uint16 rep,
978  DiInputPixel *&pixel_data,
979  vil_pixel_format &act_format)
980  {
981  Uint32 firstFragment = 0;
982  if ( rep == 0 && stored <= 8 ) {
983  act_format = VIL_PIXEL_FORMAT_BYTE;
984  pixel_data = new DiInputPixelTemplate<InT,Uint8>( document, alloc, stored, high, 0, num_samples, nplanes, nullptr, firstFragment );
985  }
986  else if ( rep == 0 && stored <= 16 ) {
987  act_format = VIL_PIXEL_FORMAT_UINT_16;
988  pixel_data = new DiInputPixelTemplate<InT,Uint16>( document, alloc, stored, high, 0, num_samples, nplanes, nullptr, firstFragment );
989  }
990  else if ( rep == 1 && stored <= 8 ) {
991  act_format = VIL_PIXEL_FORMAT_SBYTE;
992  pixel_data = new DiInputPixelTemplate<InT,Sint8>( document, alloc, stored, high, 0, num_samples, nplanes, nullptr, firstFragment );
993  }
994  else if ( rep == 1 && stored <= 16 ) {
995  act_format = VIL_PIXEL_FORMAT_INT_16;
996  pixel_data = new DiInputPixelTemplate<InT,Sint16>( document, alloc, stored, high, 0, num_samples, nplanes, nullptr, firstFragment );
997  }
998  }
999 
1000  template<class IntType, class OutType>
1001  void
1002  rescale_values( IntType const* int_begin,
1003  unsigned num_samples,
1004  OutType* float_begin,
1005  Float64 slope, Float64 intercept )
1006  {
1007  IntType const* const int_end = int_begin + num_samples;
1008  for ( ; int_begin != int_end; ++int_begin, ++float_begin ) {
1009  *float_begin = static_cast<OutType>( *int_begin * slope + intercept );
1010  }
1011  }
1012 } // anonymous namespace
1013 #ifdef MIXED_ENDIAN
1014 static unsigned short swap_short(unsigned short v)
1015 {
1016  return (v << 8)
1017  | (v >> 8);
1018 }
1019 
1020 static void swap_shorts(unsigned short *ip, unsigned short *op, int count)
1021 {
1022  while (count)
1023  {
1024  *op++ = swap_short(*ip++);
1025  count--;
1026  }
1027 }
1028 #endif //MIXED_ENDIAN
1029 static
1030 void
1031 read_pixels_into_buffer(DiDocument* doc,
1032  unsigned num_samples,
1033  unsigned nplanes,
1034  Uint16 alloc,
1035  Uint16 stored,
1036  Uint16 high,
1037  Uint16 rep,
1038  Float64 slope,
1039  Float64 intercept,
1040  vil_memory_chunk_sptr& out_buf,
1041  vil_pixel_format& out_format)
1042 {
1043 
1044  // This will be the "true" pixel buffer type after the overlay
1045  // planes are removed and the pixel bits shifted to the lowest bits
1046  // of the bytes.
1047  //
1049 
1050  // First convert from the stored src pixels to the actual
1051  // pixels. This is an integral type to integral type conversion.
1052  // Make sure pixel_data is deleted before this function exits!
1053  //
1054  DiInputPixel* pixel_data = 0;
1055  if ( doc->getPixelData()->getVR() == EVR_OW ) {
1056  convert_src_type((Uint16 *) 0, doc, num_samples, nplanes, alloc, stored, high, rep, pixel_data, act_format);
1057  }
1058  else {
1059  convert_src_type((Uint8 *) 0, doc, num_samples, nplanes, alloc, stored, high, rep, pixel_data, act_format);
1060  }
1061 
1062 #ifdef MIXED_ENDIAN
1063 #ifdef NO_OFFSET
1064  slope = 1; intercept = 0;
1065  if (act_format == VIL_PIXEL_FORMAT_SBYTE)
1066  act_format = VIL_PIXEL_FORMAT_BYTE;
1067  if (act_format == VIL_PIXEL_FORMAT_INT_16)
1068  act_format = VIL_PIXEL_FORMAT_UINT_16;
1069 #endif //NO_OFFSET
1070  bool swap_data = false;
1071  unsigned short* temp1 = new unsigned short[num_samples];
1072  unsigned short* temp2 =
1073  reinterpret_cast<unsigned short*>(pixel_data->getData());
1074  swap_shorts(temp2, temp1, num_samples);
1075  vxl_byte* temp3 = reinterpret_cast<vxl_byte*>(temp1);
1076 #endif //MIXED_ENDIAN
1077  // On error, return without doing anything
1078  if ( pixel_data == 0 ) {
1079  return;
1080  }
1081 
1082  // The data has been copied and converted. Release the source.
1083  doc->getPixelData()->clear();
1084 
1085  // Now, the actual buffer is good, or else we need to rescale
1086  //
1087  if ( slope == 1 && intercept == 0 ) {
1088  out_format = act_format;
1089 
1090  // There isn't an easy way to wrap a vil_memory_chunk around the
1091  // converted pixel data, since we don't know the array type. If we
1092  // could pass a void* to vil_memory_chunk, it will call the delete
1093  // the buffer assuming a char[] array, which it may not be. This
1094  // causes undefined behaviour. For the moment, we take the hit and
1095  // do a memcpy.
1096  //
1097  out_buf = new vil_memory_chunk( num_samples * ((stored+7)/8), VIL_PIXEL_FORMAT_BYTE );
1098 #ifdef MIXED_ENDIAN
1099  std::memcpy( out_buf->data(), temp3, out_buf->size() );
1100 #else
1101  std::memcpy( out_buf->data(), pixel_data->getData(), out_buf->size() );
1102 #endif //MIXED_ENDIAN
1103  }
1104  else {
1105  out_buf = new vil_memory_chunk( num_samples * sizeof(float), VIL_PIXEL_FORMAT_FLOAT );
1106  out_format = VIL_PIXEL_FORMAT_FLOAT;
1107 #ifdef MIXED_ENDIAN
1108  void* in_begin = reinterpret_cast<void*>(temp1);
1109 #else
1110  void* in_begin = const_cast<void*>(pixel_data->getData());
1111 #endif //MIXED_ENDIAN
1112  float* out_begin = static_cast<float*>( out_buf->data() );
1113 
1114  switch ( act_format )
1115  {
1116  case VIL_PIXEL_FORMAT_BYTE:
1117  rescale_values( (vxl_byte*)in_begin, num_samples, out_begin, slope, intercept );
1118  break;
1120  rescale_values( (vxl_sbyte*)in_begin, num_samples, out_begin, slope, intercept );
1121  break;
1123  rescale_values( (vxl_uint_16*)in_begin, num_samples, out_begin, slope, intercept );
1124  break;
1126  rescale_values( (vxl_sint_16*)in_begin, num_samples, out_begin, slope, intercept );
1127  break;
1128  default:
1129  std::cerr << "vil_dicom ERROR: unexpected internal pixel format\n";
1130  }
1131  }
1132 
1133 #ifdef MIXED_ENDIAN
1134  delete [] temp1;
1135 #endif //MIXED_ENDIAN
1136 
1137  delete pixel_data;
1138 }
1139 
1140 #endif // HAS_DCMTK
vil_dicom_header_type_of< vil_dicom_header_US >::type small_im_pix_val_
const vxl_uint_16 VIL_DICOM_HEADER_NSPHILIPSGROUP
Stream interface for VIL image loaders.
An abstract base class of smart pointers to actual image data in memory.
vil_pixel_format
Describes the type of the concrete data.
vil_dicom_header_type_of< vil_dicom_header_CS >::type phase_enc_dir_
virtual bool view_fits(const vil_image_view_base &im, unsigned i0, unsigned j0)
Check that a view will fit into the data at the given offset.
vil_dicom_header_type_of< vil_dicom_header_CS >::type modality_
vil_dicom_header_type_of< vil_dicom_header_IS >::type acquisition_number_
vil_dicom_header_type_of< vil_dicom_header_IS >::type echo_train_length_
vil_dicom_header_type_of< vil_dicom_header_CS >::type angio_flag_
vil_dicom_header_type_of< vil_dicom_header_IS >::type echo_numbers_
vil_dicom_header_type_of< vil_dicom_header_DS >::type spacing_x_
virtual char const * tag() const
Return a character string which uniquely identifies this format.
vil_dicom_header_type_of< vil_dicom_header_US >::type exposedarea_y_
vil_dicom_header_type_of< vil_dicom_header_US >::type allocated_bits_
vil_dicom_header_type_of< vil_dicom_header_DS >::type sar_
virtual vil_image_resource_sptr make_input_image(vil_stream *vs)
Attempt to make a generic_image which will read from vil_stream vs.
vil_dicom_header_type_of< vil_dicom_header_IS >::type series_number_
vil_dicom_header_type_of< vil_dicom_header_SH >::type station_name_
vil_dicom_header_type_of< vil_dicom_header_DS >::type trigger_time_
vil_dicom_header_type_of< vil_dicom_header_US >::type size_x_
vil_dicom_header_type_of< vil_dicom_header_IS >::type images_in_acq_
vil_dicom_header_type_of< vil_dicom_header_LO >::type manufacturer_
#define vil_property_pixel_size
Pixel width in metres.
Definition: vil_property.h:53
vil_dicom_header_type_of< vil_dicom_header_CS >::type sequence_var_
vil_dicom_header_type_of< vil_dicom_header_AS >::type patient_age_
vil_dicom_header_type_of< vil_dicom_header_PN >::type operator_name_
vil_dicom_header_type_of< vil_dicom_header_DS >::type window_centre_
vil_dicom_header_type_of< vil_dicom_header_IS >::type heart_rate_
vil_dicom_header_type_of< vil_dicom_header_LO >::type series_desc_
vil_dicom_header_type_of< vil_dicom_header_LO >::type institution_name_
vil_dicom_image(vil_stream *is, unsigned ni, unsigned nj, unsigned nplanes, vil_pixel_format format)
void vil_dicom_header_info_clear(vil_dicom_header_info &info)
Clears a header info struct.
virtual void seek(vil_streampos position)=0
Goto file pointer.
virtual bool interpret_hologic_header(float &xpixSize, float &ypixSize)
try and interpret the hologic comments section to extract pixel size.
vil_dicom_header_type_of< vil_dicom_header_LO >::type patient_id_
vil_dicom_header_type_of< vil_dicom_header_DS >::type number_of_averages_
vil_dicom_header_type_of< vil_dicom_header_PN >::type att_phys_name_
virtual vil_streampos read(void *buf, vil_streampos n)=0
Read n bytes into buf. Returns number of bytes read.
Exceptions thrown by vil, and a mechanism for turning them off.
vil_dicom_header_type_of< vil_dicom_header_IS >::type card_num_images_
std::vector< vil_dicom_header_type_of< vil_dicom_header_DS >::type > image_orient_
vil_dicom_header_info header_
Definition: vil_dicom.h:39
vil_dicom_header_type_of< vil_dicom_header_DS >::type flip_angle_
vil_dicom_header_type_of< vil_dicom_header_DS >::type reconst_diameter_
vil_dicom_header_type_of< vil_dicom_header_US >::type size_y_
std::vector< vil_dicom_header_type_of< vil_dicom_header_DS >::type > image_pos_
const vxl_uint_16 VIL_DICOM_HEADER_PROCEDUREGROUP
vil_dicom_header_type_of< vil_dicom_header_DS >::type res_slope_
vil_dicom_header_type_of< vil_dicom_header_UI >::type sop_cl_uid_
#define vil_property_quantisation_depth
The quantisation depth of pixel components.
Definition: vil_property.h:67
char const * file_format() const
Return a string describing the file format.
Reader/Writer for DICOM format 2D images.
vil_dicom_header_type_of< vil_dicom_header_FD >::type real_world_value_slope_
vil_dicom_header_type_of< vil_dicom_header_CS >::type image_id_type_
vil_dicom_header_type_of< vil_dicom_header_PN >::type patient_name_
vil_dicom_header_type_of< vil_dicom_header_LT >::type patient_hist_
const vxl_uint_16 VIL_DICOM_HEADER_RELATIONSHIPGROUP
vil_dicom_header_type_of< vil_dicom_header_DS >::type imager_spacing_y_
vil_dicom_header_type_of< vil_dicom_header_DS >::type inversion_time_
vil_dicom_header_type_of< vil_dicom_header_DA >::type series_date_
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
vil_dicom_header_type_of< vil_dicom_header_SH >::type sequence_name_
virtual void correct_manufacturer_discrepancies()
correct known manufacturers drop-offs in header data!.
vil_dicom_header_type_of< vil_dicom_header_DS >::type echo_time_
#define v
vil_dicom_header_type_of< vil_dicom_header_US >::type pixel_padding_val_
Indicates that some reference was made to pixels beyond the bounds of an image.
Definition: vil_exception.h:81
vil_dicom_header_type_of< vil_dicom_header_US >::type high_bit_
virtual enum vil_pixel_format pixel_format() const
Pixel Format.
const vxl_uint_16 VIL_DICOM_HEADER_ACQUISITIONGROUP
vil_dicom_header_type_of< vil_dicom_header_DA >::type acquisition_date_
DICOM information read from the header.
const vxl_uint_16 VIL_DICOM_HEADER_IDENTIFYINGGROUP
vil_dicom_header_type_of< vil_dicom_header_TM >::type image_time_
vil_dicom_header_type_of< vil_dicom_header_US >::type size_z_
vil_dicom_header_type_of< vil_dicom_header_IS >::type image_number_
vil_dicom_header_type_of< vil_dicom_header_CS >::type patient_sex_
vil_dicom_header_type_of< vil_dicom_header_US >::type large_im_pix_val_
virtual unsigned ni() const
Dimensions: Planes x ni x nj.
vil_dicom_header_type_of< vil_dicom_header_US >::type pix_samps_
vil_dicom_header_type_of< vil_dicom_header_SH >::type accession_number_
vil_dicom_header_type_of< vil_dicom_header_DA >::type image_date_
vil_dicom_header_type_of< vil_dicom_header_TM >::type study_time_
vil_dicom_header_type_of< vil_dicom_header_UI >::type ser_ins_uid_
vil_dicom_header_type_of< vil_dicom_header_DS >::type pixel_bandwidth_
vil_dicom_header_type_of< vil_dicom_header_US >::type pix_rep_
vil_image_view_base_sptr get_copy_view() const
Create a read/write view of a copy of all the data.
A base class reference-counting view of some image data.
There is no class or function called vil_property.
vil_dicom_header_type_of< vil_dicom_header_DS >::type mag_field_strength_
vil_dicom_header_type_of< vil_dicom_header_DS >::type window_width_
Ref. counted block of data on the heap.
vil_dicom_header_type_of< vil_dicom_header_DS >::type repetition_time_
Make a new image.
vil_dicom_header_type_of< vil_dicom_header_IS >::type trigger_window_
vil_dicom_header_type_of< vil_dicom_header_PN >::type ref_phys_name_
vil_dicom_header_type_of< vil_dicom_header_SH >::type study_id_
const vxl_uint_16 VIL_DICOM_HEADER_IMAGEGROUP
vil_dicom_header_type_of< vil_dicom_header_DS >::type philips_private_slope_
vil_dicom_header_type_of< vil_dicom_header_LO >::type study_desc_
vil_dicom_header_type_of< vil_dicom_header_ST >::type institution_addr_
vil_dicom_header_type_of< vil_dicom_header_LO >::type model_name_
vil_dicom_header_type_of< vil_dicom_header_DS >::type philips_private_intercept_
vil_dicom_header_type_of< vil_dicom_header_DS >::type slice_thickness_
vil_dicom_header_type_of< vil_dicom_header_CS >::type mr_acq_type_
void vil_exception_warning(T exception)
Throw an exception indicating a potential problem.
Definition: vil_exception.h:37
vil_dicom_header_type_of< vil_dicom_header_DA >::type patient_dob_
vil_dicom_header_type_of< vil_dicom_header_UI >::type frame_of_ref_
vil_dicom_header_type_of< vil_dicom_header_FD >::type real_world_value_intercept_
Representation of a generic image source or destination.
vil_dicom_header_type_of< vil_dicom_header_CS >::type scanning_seq_
virtual bool put_view(const vil_image_view_base &im, unsigned i0, unsigned j0)
Put the data in this view back into the image source.
virtual unsigned nplanes() const
Dimensions: Planes x ni x nj.
vil_dicom_header_type_of< vil_dicom_header_DS >::type res_intercept_
vil_dicom_header_type_of< vil_dicom_header_UI >::type stud_ins_uid_
vil_dicom_header_type_of< vil_dicom_header_DS >::type spacing_y_
vil_dicom_header_type_of< vil_dicom_header_SH >::type receiving_coil_
vil_dicom_header_type_of< vil_dicom_header_DS >::type spacing_slice_
vil_dicom_header_type_of< vil_dicom_header_CS >::type pat_orient_
vil_dicom_header_type_of< vil_dicom_header_US >::type exposedarea_x_
vil_dicom_header_type_of< vil_dicom_header_UI >::type sop_in_uid_
vil_dicom_header_type_of< vil_dicom_header_CS >::type patient_pos_
vil_dicom_header_type_of< vil_dicom_header_CS >::type scan_options_
vil_dicom_header_type_of< vil_dicom_header_CS >::type photo_interp_
virtual vil_image_resource_sptr make_output_image(vil_stream *vs, unsigned ni, unsigned nj, unsigned nplanes, vil_pixel_format format)
vil_image_resource_sptr pixels_
Definition: vil_dicom.h:40
Generic image implementation for DICOM files.
Definition: vil_dicom.h:37
vil_dicom_header_type_of< vil_dicom_header_LO >::type software_vers_
vil_image_view_base_sptr get_view() const
Create a read/write view of all the data.
vil_dicom_header_type_of< vil_dicom_header_LO >::type protocol_name_
vil_dicom_header_type_of< vil_dicom_header_LT >::type image_comments_
bool get_property(char const *tag, void *prop=0) const
Extra property information.
vil_dicom_header_type_of< vil_dicom_header_TM >::type acquisition_time_
vil_dicom_header_type_of< vil_dicom_header_DS >::type imager_spacing_x_
vil_dicom_header_type_of< vil_dicom_header_TM >::type series_time_
vil_dicom_header_type_of< vil_dicom_header_DA >::type study_date_
virtual unsigned nj() const
Dimensions: Planes x ni x nj.
const vxl_uint_16 VIL_DICOM_HEADER_PATIENTINFOGROUP
vil_dicom_header_type_of< vil_dicom_header_LO >::type pos_ref_ind_
vil_dicom_header_type_of< vil_dicom_header_DS >::type patient_weight_
vil_dicom_header_type_of< vil_dicom_header_US >::type stored_bits_