00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include <vil/vil_config.h>
00009 #if HAS_DCMTK
00010
00011 #include "vil_dicom.h"
00012
00013 #include <vcl_cassert.h>
00014 #include <vcl_iostream.h>
00015 #include <vcl_sstream.h>
00016 #include <vcl_cstring.h>
00017 #include <vcl_cstdlib.h>
00018 #include <vcl_vector.h>
00019
00020 #include <vxl_config.h>
00021
00022 #include <vil/vil_property.h>
00023 #include <vil/vil_stream.h>
00024 #include <vil/vil_image_resource.h>
00025 #include <vil/vil_new.h>
00026 #include <vil/vil_image_view.h>
00027 #include <vil/vil_pixel_format.h>
00028 #include <vil/vil_exception.h>
00029 #ifdef __BORLANDC__
00030
00031 # pragma warn -8004 // 'smask' is assigned a value that is never used in function
00032 #endif
00033
00034 #include <dcfilefo.h>
00035 #include <dcmetinf.h>
00036 #include <dcdatset.h>
00037 #include <dctagkey.h>
00038 #include <dcdeftag.h>
00039 #include <dcstack.h>
00040 #include <diinpxt.h>
00041
00042 #include "vil_dicom_stream.h"
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 char const* vil_dicom_format_tag = "dicom";
00056
00057
00058 vil_image_resource_sptr vil_dicom_file_format::make_input_image(vil_stream* vs)
00059 {
00060 bool is_dicom = false;
00061
00062 char magic[ DCM_MagicLen ];
00063 vs->seek( DCM_PreambleLen );
00064 if ( vs->read( magic, DCM_MagicLen ) == DCM_MagicLen ) {
00065 if ( vcl_strncmp( magic, DCM_Magic, DCM_MagicLen ) == 0 ) {
00066 is_dicom = true;
00067 }
00068 }
00069
00070 if ( is_dicom )
00071 return new vil_dicom_image( vs );
00072 else
00073 return 0;
00074 }
00075
00076 vil_image_resource_sptr vil_dicom_file_format::make_output_image(vil_stream* ,
00077 unsigned ,
00078 unsigned ,
00079 unsigned ,
00080 vil_pixel_format)
00081 {
00082 vcl_cerr << "ERROR: vil_dicom_file doesn't support output yet\n";
00083 return 0;
00084 #if 0
00085
00086 if (nplanes != 1 || format != VIL_PIXEL_FORMAT_INT_32)
00087 {
00088 vcl_cerr << "ERROR: vil_dicom_file_format::make_output_image\n"
00089 << " Can only create DICOM images with a single plane\n"
00090 << " and 32-bit integer pixels\n";
00091 return 0;
00092 }
00093 return new vil_dicom_image(vs, ni, nj, nplanes, format);
00094 #endif
00095 }
00096
00097 char const* vil_dicom_file_format::tag() const
00098 {
00099 return vil_dicom_format_tag;
00100 }
00101
00102
00103
00104
00105
00106 static
00107 void
00108 read_header( DcmObject* dataset, vil_dicom_header_info& i );
00109
00110 static
00111 void
00112 read_pixels_into_buffer(DcmPixelData* pixels,
00113 unsigned num_samples,
00114 Uint16 alloc,
00115 Uint16 stored,
00116 Uint16 high,
00117 Uint16 rep,
00118 Float64 slope,
00119 Float64 intercept,
00120 vil_memory_chunk_sptr& out_buf,
00121 vil_pixel_format& out_format);
00122
00123
00124 vil_dicom_image::vil_dicom_image(vil_stream* vs)
00125 : pixels_( 0 )
00126 {
00127 vil_dicom_header_info_clear( header_ );
00128
00129 vil_dicom_stream_input dcis( vs );
00130
00131 DcmFileFormat ffmt;
00132 ffmt.transferInit();
00133 OFCondition cond = ffmt.read( dcis );
00134 ffmt.transferEnd();
00135
00136 if ( cond != EC_Normal ) {
00137 vcl_cerr << "vil_dicom ERROR: could not read file (" << cond.text() << ")\n"
00138 << "And the error code is: " << cond.code() << vcl_endl;
00139
00140 return;
00141 }
00142
00143 DcmDataset& dset = *ffmt.getDataset();
00144 read_header( &dset, header_ );
00145
00146
00147 correct_manufacturer_discrepancies();
00148
00149
00150
00151
00152 if ( dset.tagExists( DCM_ModalityLUTSequence ) ) {
00153 vcl_cerr << "vil_dicom ERROR: don't know (yet) how to handle modality LUTs\n";
00154 return;
00155 }
00156
00157
00158
00159
00160
00161 Float64 slope, intercept;
00162 if ( dset.findAndGetFloat64( DCM_RescaleSlope, slope ) != EC_Normal )
00163 slope = 1;
00164 if ( dset.findAndGetFloat64( DCM_RescaleIntercept, intercept ) != EC_Normal )
00165 intercept = 0;
00166
00167
00168
00169 #define Stringify( v ) #v
00170 #define MustRead( func, key, var ) \
00171 do { \
00172 if ( dset. func( key, var ) != EC_Normal ) { \
00173 vcl_cerr << "vil_dicom ERROR: couldn't read " Stringify(key) "; can't handle\n"; \
00174 return; \
00175 }} while (false)
00176
00177 Uint16 bits_alloc, bits_stored, high_bit, pixel_rep;
00178
00179 MustRead( findAndGetUint16, DCM_BitsAllocated, bits_alloc );
00180 MustRead( findAndGetUint16, DCM_BitsStored, bits_stored );
00181 MustRead( findAndGetUint16, DCM_HighBit, high_bit );
00182 MustRead( findAndGetUint16, DCM_PixelRepresentation, pixel_rep );
00183
00184 #undef MustRead
00185 #undef Stringify
00186
00187
00188
00189
00190 vil_memory_chunk_sptr pixel_buf;
00191 vil_pixel_format pixel_format = VIL_PIXEL_FORMAT_UNKNOWN;
00192
00193
00194
00195 {
00196 DcmPixelData* pixels = 0;
00197 DcmStack stack;
00198 if ( dset.search( DCM_PixelData, stack, ESM_fromHere, true ) == EC_Normal )
00199 {
00200 if ( stack.card() == 0 ) {
00201 vcl_cerr << "vil_dicom ERROR: no pixel data found\n";
00202 return;
00203 }
00204 else {
00205 assert( stack.top()->ident() == EVR_PixelData );
00206 pixels = static_cast<DcmPixelData*>(stack.top());
00207 }
00208 }
00209 unsigned num_samples = ni() * nj() * nplanes();
00210 read_pixels_into_buffer(pixels, num_samples,
00211 bits_alloc, bits_stored, high_bit, pixel_rep,
00212 slope, intercept,
00213 pixel_buf, pixel_format);
00214 }
00215
00216
00217
00218 #define DOCASE( fmt ) \
00219 case fmt: { \
00220 typedef vil_pixel_format_type_of<fmt>::component_type T; \
00221 pixels_ = vil_new_image_resource_of_view( \
00222 vil_image_view<T>(pixel_buf, \
00223 (T*)pixel_buf->data(), \
00224 ni(), nj(), nplanes(), \
00225 nplanes(), ni()*nplanes(), 1));\
00226 } break
00227
00228 switch ( pixel_format ) {
00229 DOCASE( VIL_PIXEL_FORMAT_UINT_16 );
00230 DOCASE( VIL_PIXEL_FORMAT_INT_16 );
00231 DOCASE( VIL_PIXEL_FORMAT_BYTE );
00232 DOCASE( VIL_PIXEL_FORMAT_SBYTE );
00233 DOCASE( VIL_PIXEL_FORMAT_FLOAT );
00234 default: vcl_cerr << "vil_dicom ERROR: unexpected pixel format\n";
00235 }
00236 #undef DOCASE
00237 }
00238
00239
00240 bool vil_dicom_image::get_property(char const* tag, void* value) const
00241 {
00242 if (vcl_strcmp(vil_property_quantisation_depth, tag)==0)
00243 {
00244 if (value)
00245 *static_cast<unsigned int*>(value) = header_.stored_bits_;
00246 return true;
00247 }
00248
00249 if (vcl_strcmp(vil_property_pixel_size, tag)==0 && value!=0)
00250 {
00251 float *pixel_size = static_cast<float*>(value);
00252 pixel_size[0] = header_.spacing_x_ / 1000.0f;
00253 pixel_size[1] = header_.spacing_y_ / 1000.0f;
00254 return true;
00255 }
00256
00257
00258 return false;
00259 }
00260
00261 char const* vil_dicom_image::file_format() const
00262 {
00263 return vil_dicom_format_tag;
00264 }
00265
00266 vil_dicom_image::vil_dicom_image(vil_stream* , unsigned ni, unsigned nj,
00267 unsigned nplanes, vil_pixel_format format)
00268 {
00269 assert(!"vil_dicom_image doesn't yet support output");
00270
00271 assert(nplanes == 1 && format == VIL_PIXEL_FORMAT_INT_32);
00272 header_.size_x_ = ni;
00273 header_.size_y_ = nj;
00274 header_.size_z_ = 1;
00275 }
00276
00277 vil_dicom_image::~vil_dicom_image()
00278 {
00279 }
00280
00281 unsigned vil_dicom_image::nplanes() const
00282 {
00283 return header_.pix_samps_;
00284 }
00285
00286 unsigned vil_dicom_image::ni() const
00287 {
00288 return header_.size_x_;
00289 }
00290
00291 unsigned vil_dicom_image::nj() const
00292 {
00293 return header_.size_y_;
00294 }
00295
00296 enum vil_pixel_format vil_dicom_image::pixel_format() const
00297 {
00298 return pixels_ ? pixels_->pixel_format() : VIL_PIXEL_FORMAT_UNKNOWN;
00299 }
00300
00301 vil_image_view_base_sptr vil_dicom_image::get_copy_view(
00302 unsigned x0, unsigned nx, unsigned y0, unsigned ny) const
00303 {
00304 return pixels_ ? pixels_->get_copy_view( x0, nx, y0, ny ) : 0;
00305 }
00306
00307 vil_image_view_base_sptr vil_dicom_image::get_view(
00308 unsigned x0, unsigned nx, unsigned y0, unsigned ny) const
00309 {
00310 return pixels_ ? pixels_->get_view( x0, nx, y0, ny ) : 0;
00311 }
00312
00313 bool vil_dicom_image::put_view(const vil_image_view_base& view,
00314 unsigned x0, unsigned y0)
00315 {
00316 assert(!"vil_dicom_image doesn't yet support output yet");
00317
00318 if (!view_fits(view, x0, y0))
00319 {
00320 vil_exception_warning(vil_exception_out_of_bounds("vil_dicom_image::put_view"));
00321 return false;
00322 }
00323
00324 return false;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 void vil_dicom_image::correct_manufacturer_discrepancies()
00337 {
00338
00339 if ( ( (header_.manufacturer_ == "HOLOGIC") || (header_.manufacturer_ == "Hologic") ) &&
00340 ( (header_.model_name_.find("QDR") != header_.model_name_.npos ) ||
00341 (header_.model_name_.find("Discovery") != header_.model_name_.npos ) ) )
00342 {
00343
00344 float xPixelSize=1.0;
00345 float yPixelSize=1.0;
00346 if (interpret_hologic_header(xPixelSize,yPixelSize))
00347 {
00348 header_.spacing_x_ = xPixelSize;
00349 header_.spacing_y_ = yPixelSize;
00350 }
00351 }
00352 }
00353
00354
00355 bool vil_dicom_image::interpret_hologic_header(float& xpixSize, float& ypixSize)
00356 {
00357
00358
00359 static const vcl_string HOLOGIC_PixelXSizeMM = "<PixelXSizeMM>";
00360 static const vcl_string HOLOGIC_PixelXSizeMM_END = "</PixelXSizeMM>";
00361 static const vcl_string HOLOGIC_PixelYSizeMM = "<PixelYSizeMM>";
00362 static const vcl_string HOLOGIC_PixelYSizeMM_END = "</PixelYSizeMM>";
00363
00364 vcl_string src = header_.image_comments_;
00365
00366 vcl_size_t ipxStart = src.find(HOLOGIC_PixelXSizeMM);
00367 if (ipxStart==src.npos) return false;
00368
00369
00370 vcl_size_t ipxEnd = src.find(HOLOGIC_PixelXSizeMM_END,ipxStart);
00371 if (ipxEnd==src.npos) return false;
00372
00373
00374 vcl_string strPixelXSizeMM="";
00375 ipxStart+= HOLOGIC_PixelXSizeMM.size();
00376 strPixelXSizeMM.append(src,ipxStart, ipxEnd-ipxStart);
00377
00378 if (strPixelXSizeMM.size()>0)
00379 {
00380
00381 vcl_stringstream translate_is(strPixelXSizeMM,vcl_stringstream::in);
00382 translate_is>>xpixSize;
00383 if (!translate_is) return false;
00384 if (xpixSize<=0.0 || xpixSize>=1.0E6)
00385 return false;
00386 }
00387 else
00388 {
00389 return false;
00390 }
00391
00392
00393 vcl_size_t ipyStart = src.find(HOLOGIC_PixelYSizeMM);
00394 if (ipyStart==src.npos) return false;
00395
00396
00397 vcl_size_t ipyEnd = src.find(HOLOGIC_PixelYSizeMM_END,ipyStart);
00398 if (ipyEnd==src.npos) return false;
00399
00400
00401 vcl_string strPixelYSizeMM="";
00402 ipyStart+= HOLOGIC_PixelYSizeMM.size();
00403 strPixelYSizeMM.append(src,ipyStart, ipyEnd-ipyStart);
00404
00405 if (strPixelYSizeMM.size()>0)
00406 {
00407
00408 vcl_stringstream translate_is(strPixelYSizeMM,vcl_stringstream::in);
00409 translate_is>>ypixSize;
00410 if (!translate_is) return false;
00411 if (ypixSize<=0.0 || ypixSize>=1.0E6)
00412 return false;
00413 }
00414 else
00415 {
00416 return false;
00417 }
00418
00419 return true;
00420 }
00421
00422
00423
00424
00425
00426
00427
00428 static
00429 DcmElement*
00430 find_element( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element )
00431 {
00432 DcmElement* result = 0;
00433 DcmTagKey key( group, element );
00434 DcmStack stack;
00435 if ( dset->search( key, stack, ESM_fromHere, true ) == EC_Normal )
00436 {
00437 if ( stack.card() == 0 ) {
00438 vcl_cerr << "vil_dicom ERROR: no results on stack\n";
00439 }
00440 else {
00441 result = static_cast<DcmElement*>(stack.top());
00442 if ( result->getVM() == 0 ) {
00443
00444 result = 0;
00445 }
00446 }
00447 }
00448
00449 return result;
00450 }
00451
00452
00453 namespace
00454 {
00455
00456
00457
00458
00459 template <int T >
00460 struct try_set;
00461
00462
00463
00464
00465 struct try_set_to_string
00466 {
00467 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vcl_string& value ) {
00468 DcmElement* e = find_element( dset, group, element );
00469 if ( e )
00470 {
00471 OFString str;
00472 if ( e->getOFString( str, 0 ) != EC_Normal ) {
00473 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
00474 }
00475 else {
00476 value = str.c_str();
00477 }
00478 }
00479 }
00480 };
00481
00482 VCL_DEFINE_SPECIALIZATION
00483 struct try_set< vil_dicom_header_AE >
00484 : public try_set_to_string
00485 {
00486 };
00487
00488 VCL_DEFINE_SPECIALIZATION
00489 struct try_set< vil_dicom_header_AS >
00490 : public try_set_to_string
00491 {
00492 };
00493
00494 VCL_DEFINE_SPECIALIZATION
00495 struct try_set< vil_dicom_header_AT >
00496 : public try_set_to_string
00497 {
00498 };
00499
00500 VCL_DEFINE_SPECIALIZATION
00501 struct try_set< vil_dicom_header_CS >
00502 : public try_set_to_string
00503 {
00504 };
00505
00506 VCL_DEFINE_SPECIALIZATION
00507 struct try_set< vil_dicom_header_DA >
00508 {
00509 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, long& value ) {
00510 DcmElement* e = find_element( dset, group, element );
00511 if ( e )
00512 {
00513 OFString str;
00514 if ( e->getOFString( str, 0 ) != EC_Normal ) {
00515 vcl_cerr << "Warning: value of ("<<group<<','<<element<<") is not string\n";
00516 }
00517 else {
00518 value = vcl_atol( str.c_str() );
00519 }
00520 }
00521 }
00522 };
00523
00524 VCL_DEFINE_SPECIALIZATION
00525 struct try_set< vil_dicom_header_DS >
00526 {
00527 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, float& value ) {
00528 DcmElement* e = find_element( dset, group, element );
00529 if ( e )
00530 {
00531 OFString str;
00532 if ( e->getOFString( str, 0 ) != EC_Normal ) {
00533 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
00534 }
00535 else {
00536 value = static_cast<float>( vcl_atof( str.c_str() ) );
00537 }
00538 }
00539 }
00540
00541 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vcl_vector<float>& value ) {
00542 DcmElement* e = find_element( dset, group, element );
00543 if ( e ) {
00544 for ( unsigned pos = 0; pos < e->getVM(); ++pos )
00545 {
00546 OFString str;
00547 if ( e->getOFString( str, pos ) != EC_Normal ) {
00548 vcl_cerr << "Warning: value of ("<<group<<','<<element<<") at " << pos << " is not string\n";
00549 }
00550 else {
00551 value.push_back( static_cast<float>( vcl_atof( str.c_str() ) ) );
00552 }
00553 }
00554 }
00555 }
00556 };
00557
00558 VCL_DEFINE_SPECIALIZATION
00559 struct try_set< vil_dicom_header_FD >
00560 {
00561 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_ieee_64& value ) {
00562 DcmElement* e = find_element( dset, group, element );
00563 if ( e ) {
00564 if ( e->getFloat64( value ) != EC_Normal ) {
00565 vcl_cerr << "Warning: value of ("<<group<<','<<element<<") is not Float64\n";
00566 }
00567 }
00568 }
00569 };
00570
00571 VCL_DEFINE_SPECIALIZATION
00572 struct try_set< vil_dicom_header_FL >
00573 {
00574 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_ieee_32& value ) {
00575 DcmElement* e = find_element( dset, group, element );
00576 if ( e ) {
00577 if ( e->getFloat32( value ) != EC_Normal ) {
00578 vcl_cerr << "Warning: value of ("<<group<<','<<element<<") is not Float32\n";
00579 }
00580 }
00581 }
00582 };
00583
00584 VCL_DEFINE_SPECIALIZATION
00585 struct try_set< vil_dicom_header_IS >
00586 {
00587 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, long& value ) {
00588 DcmElement* e = find_element( dset, group, element );
00589 if ( e )
00590 {
00591 OFString str;
00592 if ( e->getOFString( str, 0 ) != EC_Normal ) {
00593 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
00594 }
00595 else {
00596 value = vcl_atol( str.c_str() );
00597 }
00598 }
00599 }
00600 };
00601
00602 VCL_DEFINE_SPECIALIZATION
00603 struct try_set< vil_dicom_header_LO >
00604 : public try_set_to_string
00605 {
00606 };
00607
00608 VCL_DEFINE_SPECIALIZATION
00609 struct try_set< vil_dicom_header_LT >
00610 : public try_set_to_string
00611 {
00612 };
00613
00614 VCL_DEFINE_SPECIALIZATION
00615 struct try_set< vil_dicom_header_OB >
00616 : public try_set_to_string
00617 {
00618 };
00619
00620 VCL_DEFINE_SPECIALIZATION
00621 struct try_set< vil_dicom_header_OW >
00622 : public try_set_to_string
00623 {
00624 };
00625
00626 VCL_DEFINE_SPECIALIZATION
00627 struct try_set< vil_dicom_header_PN >
00628 : public try_set_to_string
00629 {
00630 };
00631
00632 VCL_DEFINE_SPECIALIZATION
00633 struct try_set< vil_dicom_header_SH >
00634 : public try_set_to_string
00635 {
00636 };
00637
00638 VCL_DEFINE_SPECIALIZATION
00639 struct try_set< vil_dicom_header_SL >
00640 {
00641 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_sint_32& value ) {
00642 DcmElement* e = find_element( dset, group, element );
00643 if ( e ) {
00644 if ( e->getSint32( reinterpret_cast<Sint32&>(value) ) != EC_Normal ) {
00645 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Sint32\n";
00646 }
00647 }
00648 }
00649 };
00650
00651 VCL_DEFINE_SPECIALIZATION
00652 struct try_set< vil_dicom_header_SQ >
00653 : public try_set_to_string
00654 {
00655 };
00656
00657 VCL_DEFINE_SPECIALIZATION
00658 struct try_set< vil_dicom_header_SS >
00659 {
00660 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_sint_16& value ) {
00661 DcmElement* e = find_element( dset, group, element );
00662 if ( e ) {
00663 if ( e->getSint16( reinterpret_cast<Sint16&>(value) ) != EC_Normal ) {
00664 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Sint16\n";
00665 }
00666 }
00667 }
00668 };
00669
00670 VCL_DEFINE_SPECIALIZATION
00671 struct try_set< vil_dicom_header_ST >
00672 : public try_set_to_string
00673 {
00674 };
00675
00676 VCL_DEFINE_SPECIALIZATION
00677 struct try_set< vil_dicom_header_TM >
00678 {
00679 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, float& value ) {
00680 DcmElement* e = find_element( dset, group, element );
00681 if ( e )
00682 {
00683 OFString str;
00684 if ( e->getOFString( str, 0 ) != EC_Normal ) {
00685 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not string\n";
00686 }
00687 else {
00688 value = static_cast<float>( vcl_atof( str.c_str() ) );
00689 }
00690 }
00691 }
00692 };
00693
00694 VCL_DEFINE_SPECIALIZATION
00695 struct try_set< vil_dicom_header_UI >
00696 : public try_set_to_string
00697 {
00698 };
00699
00700 VCL_DEFINE_SPECIALIZATION
00701 struct try_set< vil_dicom_header_UL >
00702 {
00703 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_uint_32& value ) {
00704 DcmElement* e = find_element( dset, group, element );
00705 if ( e ) {
00706 if ( e->getUint32( reinterpret_cast<Uint32&>(value) ) != EC_Normal ) {
00707 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Uint32\n";
00708 }
00709 }
00710 }
00711 };
00712
00713 VCL_DEFINE_SPECIALIZATION
00714 struct try_set< vil_dicom_header_UN >
00715 : public try_set_to_string
00716 {
00717 };
00718
00719 VCL_DEFINE_SPECIALIZATION
00720 struct try_set< vil_dicom_header_US >
00721 {
00722 static void proc( DcmObject* dset, vxl_uint_16 group, vxl_uint_16 element, vxl_uint_16& value ) {
00723 DcmElement* e = find_element( dset, group, element );
00724 if ( e ) {
00725 if ( e->getUint16( value ) != EC_Normal ) {
00726 vcl_cerr << "vil_dicom Warning: value of ("<<group<<','<<element<<") is not Uint16\n";
00727 }
00728 }
00729 }
00730 };
00731
00732 VCL_DEFINE_SPECIALIZATION
00733 struct try_set< vil_dicom_header_UT >
00734 : public try_set_to_string
00735 {
00736 };
00737 }
00738
00739 static
00740 void
00741 read_header( DcmObject* f, vil_dicom_header_info& i )
00742 {
00743 vxl_uint_16 group;
00744
00745 #define ap_join(A,B) A ## B
00746 #define ap_type(X) ap_join( vil_dicom_header_, X )
00747 #define ap_el(X) ap_join( VIL_DICOM_HEADER_, X )
00748
00749 group = VIL_DICOM_HEADER_IDENTIFYINGGROUP;
00750 try_set< ap_type(CS) >::proc( f, group, ap_el(IDIMAGETYPE), i.image_id_type_ );
00751 try_set< ap_type(UI) >::proc( f, group, ap_el(IDSOPCLASSID), i.sop_cl_uid_ );
00752 try_set< ap_type(UI) >::proc( f, group, ap_el(IDSOPINSTANCEID), i.sop_in_uid_ );
00753 try_set< ap_type(DA) >::proc( f, group, ap_el(IDSTUDYDATE), i.study_date_ );
00754 try_set< ap_type(DA) >::proc( f, group, ap_el(IDSERIESDATE), i.series_date_ );
00755 try_set< ap_type(DA) >::proc( f, group, ap_el(IDACQUISITIONDATE), i.acquisition_date_ );
00756 try_set< ap_type(DA) >::proc( f, group, ap_el(IDIMAGEDATE), i.image_date_ );
00757 try_set< ap_type(TM) >::proc( f, group, ap_el(IDSTUDYTIME), i.study_time_ );
00758 try_set< ap_type(TM) >::proc( f, group, ap_el(IDSERIESTIME), i.series_time_ );
00759 try_set< ap_type(TM) >::proc( f, group, ap_el(IDACQUISITIONTIME), i.acquisition_time_ );
00760 try_set< ap_type(TM) >::proc( f, group, ap_el(IDIMAGETIME), i.image_time_ );
00761 try_set< ap_type(SH) >::proc( f, group, ap_el(IDACCESSIONNUMBER), i.accession_number_ );
00762 try_set< ap_type(CS) >::proc( f, group, ap_el(IDMODALITY), i.modality_ );
00763 try_set< ap_type(LO) >::proc( f, group, ap_el(IDMANUFACTURER), i.manufacturer_ );
00764 try_set< ap_type(LO) >::proc( f, group, ap_el(IDINSTITUTIONNAME), i.institution_name_ );
00765 try_set< ap_type(ST) >::proc( f, group, ap_el(IDINSTITUTIONADDRESS),i.institution_addr_ );
00766 try_set< ap_type(PN) >::proc( f, group, ap_el(IDREFERRINGPHYSICIAN),i.ref_phys_name_ );
00767 try_set< ap_type(SH) >::proc( f, group, ap_el(IDSTATIONNAME), i.station_name_ );
00768 try_set< ap_type(LO) >::proc( f, group, ap_el(IDSTUDYDESCRIPTION), i.study_desc_ );
00769 try_set< ap_type(LO) >::proc( f, group, ap_el(IDSERIESDESCRIPTION), i.series_desc_ );
00770 try_set< ap_type(PN) >::proc( f, group, ap_el(IDATTENDINGPHYSICIAN),i.att_phys_name_);
00771 try_set< ap_type(PN) >::proc( f, group, ap_el(IDOPERATORNAME), i.operator_name_ );
00772 try_set< ap_type(LO) >::proc( f, group, ap_el(IDMANUFACTURERMODEL), i.model_name_ );
00773
00774 group = VIL_DICOM_HEADER_PATIENTINFOGROUP;
00775 try_set< ap_type(PN) >::proc( f, group, ap_el(PIPATIENTNAME), i.patient_name_ );
00776 try_set< ap_type(LO) >::proc( f, group, ap_el(PIPATIENTID), i.patient_id_ );
00777 try_set< ap_type(DA) >::proc( f, group, ap_el(PIPATIENTBIRTHDATE),i.patient_dob_ );
00778 try_set< ap_type(CS) >::proc( f, group, ap_el(PIPATIENTSEX), i.patient_sex_ );
00779 try_set< ap_type(AS) >::proc( f, group, ap_el(PIPATIENTAGE), i.patient_age_ );
00780 try_set< ap_type(DS) >::proc( f, group, ap_el(PIPATIENTWEIGHT), i.patient_weight_ );
00781 try_set< ap_type(LT) >::proc( f, group, ap_el(PIPATIENTHISTORY), i.patient_hist_ );
00782
00783 group = VIL_DICOM_HEADER_ACQUISITIONGROUP;
00784 try_set< ap_type(CS) >::proc( f, group, ap_el(AQSCANNINGSEQUENCE), i.scanning_seq_ );
00785 try_set< ap_type(CS) >::proc( f, group, ap_el(AQSEQUENCEVARIANT), i.sequence_var_ );
00786 try_set< ap_type(CS) >::proc( f, group, ap_el(AQSCANOPTIONS), i.scan_options_ );
00787 try_set< ap_type(CS) >::proc( f, group, ap_el(AQMRACQUISITIONTYPE), i.mr_acq_type_ );
00788 try_set< ap_type(SH) >::proc( f, group, ap_el(AQSEQUENCENAME), i.sequence_name_ );
00789 try_set< ap_type(CS) >::proc( f, group, ap_el(AQANGIOFLAG), i.angio_flag_ );
00790 try_set< ap_type(DS) >::proc( f, group, ap_el(AQSLICETHICKNESS), i.slice_thickness_ );
00791 try_set< ap_type(DS) >::proc( f, group, ap_el(AQREPETITIONTIME), i.repetition_time_ );
00792 try_set< ap_type(DS) >::proc( f, group, ap_el(AQECHOTIME), i.echo_time_ );
00793 try_set< ap_type(DS) >::proc( f, group, ap_el(AQINVERSIONTIME), i.inversion_time_ );
00794 try_set< ap_type(DS) >::proc( f, group, ap_el(AQNUMBEROFAVERAGES), i.number_of_averages_ );
00795 try_set< ap_type(IS) >::proc( f, group, ap_el(AQECHONUMBERS), i.echo_numbers_ );
00796 try_set< ap_type(DS) >::proc( f, group, ap_el(AQMAGNETICFIELDSTRENGTH), i.mag_field_strength_);
00797 try_set< ap_type(DS) >::proc( f, group, ap_el(AQSLICESPACING), i.spacing_slice_ );
00798 try_set< ap_type(IS) >::proc( f, group, ap_el(AQECHOTRAINLENGTH), i.echo_train_length_ );
00799 try_set< ap_type(DS) >::proc( f, group, ap_el(AQPIXELBANDWIDTH), i.pixel_bandwidth_ );
00800 try_set< ap_type(LO) >::proc( f, group, ap_el(AQSOFTWAREVERSION), i.software_vers_ );
00801 try_set< ap_type(LO) >::proc( f, group, ap_el(AQPROTOCOLNAME), i.protocol_name_ );
00802 try_set< ap_type(IS) >::proc( f, group, ap_el(AQHEARTRATE), i.heart_rate_ );
00803 try_set< ap_type(IS) >::proc( f, group, ap_el(AQCARDIACNUMBEROFIMAGES), i.card_num_images_ );
00804 try_set< ap_type(IS) >::proc( f, group, ap_el(AQTRIGGERWINDOW), i.trigger_window_ );
00805 try_set< ap_type(DS) >::proc( f, group, ap_el(AQRECONTRUCTIONDIAMETER), i.reconst_diameter_ );
00806 try_set< ap_type(SH) >::proc( f, group, ap_el(AQRECEIVINGCOIL), i.receiving_coil_ );
00807 try_set< ap_type(CS) >::proc( f, group, ap_el(AQPHASEENCODINGDIRECTION),i.phase_enc_dir_ );
00808 try_set< ap_type(DS) >::proc( f, group, ap_el(AQFLIPANGLE), i.flip_angle_ );
00809 try_set< ap_type(DS) >::proc( f, group, ap_el(AQSAR), i.sar_ );
00810 try_set< ap_type(CS) >::proc( f, group, ap_el(AQPATIENTPOSITION), i.patient_pos_ );
00811
00812 group = VIL_DICOM_HEADER_RELATIONSHIPGROUP;
00813 try_set< ap_type(UI) >::proc( f, group, ap_el(RSSTUDYINSTANCEUID), i.stud_ins_uid_ );
00814 try_set< ap_type(UI) >::proc( f, group, ap_el(RSSERIESINSTANCEUID), i.ser_ins_uid_ );
00815 try_set< ap_type(SH) >::proc( f, group, ap_el(RSSTUDYID), i.study_id_ );
00816 try_set< ap_type(IS) >::proc( f, group, ap_el(RSSERIESNUMBER), i.series_number_ );
00817 try_set< ap_type(IS) >::proc( f, group, ap_el(RSAQUISITIONNUMBER), i.acquisition_number_ );
00818 try_set< ap_type(IS) >::proc( f, group, ap_el(RSIMAGENUMBER), i.image_number_ );
00819 try_set< ap_type(CS) >::proc( f, group, ap_el(RSPATIENTORIENTATION), i.pat_orient_ );
00820 try_set< ap_type(DS) >::proc( f, group, ap_el(RSIMAGEPOSITION), i.image_pos_ );
00821 try_set< ap_type(DS) >::proc( f, group, ap_el(RSIMAGEORIENTATION), i.image_orient_ );
00822 try_set< ap_type(UI) >::proc( f, group, ap_el(RSFRAMEOFREFERENCEUID),i.frame_of_ref_ );
00823 try_set< ap_type(IS) >::proc( f, group, ap_el(RSIMAGESINACQUISITION),i.images_in_acq_);
00824 try_set< ap_type(LO) >::proc( f, group, ap_el(RSPOSITIONREFERENCE), i.pos_ref_ind_ );
00825 try_set< ap_type(LT) >::proc( f, group, ap_el(RSIMAGECOMMENTS), i.image_comments_ );
00826
00827 group = VIL_DICOM_HEADER_IMAGEGROUP;
00828 try_set< ap_type(US) >::proc( f, group, ap_el(IMSAMPLESPERPIXEL), i.pix_samps_ );
00829 try_set< ap_type(CS) >::proc( f, group, ap_el(IMPHOTOMETRICINTERP), i.photo_interp_ );
00830 try_set< ap_type(US) >::proc( f, group, ap_el(IMROWS), i.size_y_ );
00831 try_set< ap_type(US) >::proc( f, group, ap_el(IMCOLUMNS), i.size_x_ );
00832 try_set< ap_type(US) >::proc( f, group, ap_el(IMPLANES), i.size_z_ );
00833 try_set< ap_type(US) >::proc( f, group, ap_el(IMBITSALLOCATED), i.allocated_bits_ );
00834 try_set< ap_type(US) >::proc( f, group, ap_el(IMBITSSTORED), i.stored_bits_ );
00835 try_set< ap_type(US) >::proc( f, group, ap_el(IMHIGHBIT), i.high_bit_ );
00836 try_set< ap_type(US) >::proc( f, group, ap_el(IMPIXELREPRESENTATION),i.pix_rep_ );
00837 try_set< ap_type(US) >::proc( f, group, ap_el(IMSMALLIMPIXELVALUE), i.small_im_pix_val_ );
00838 try_set< ap_type(US) >::proc( f, group, ap_el(IMLARGEIMPIXELVALUE), i.large_im_pix_val_ );
00839 try_set< ap_type(US) >::proc( f, group, ap_el(IMPIXELPADDINGVALUE), i.pixel_padding_val_ );
00840 try_set< ap_type(DS) >::proc( f, group, ap_el(IMWINDOWCENTER), i.window_centre_ );
00841 try_set< ap_type(DS) >::proc( f, group, ap_el(IMWINDOWWIDTH), i.window_width_ );
00842 try_set< ap_type(DS) >::proc( f, group, ap_el(IMRESCALEINTERCEPT), i.res_intercept_ );
00843 try_set< ap_type(DS) >::proc( f, group, ap_el(IMRESCALESLOPE), i.res_slope_ );
00844
00845 typedef vil_dicom_header_type_of<vil_dicom_header_DS>::type DS_type;
00846 vcl_vector<DS_type> ps;
00847 try_set< ap_type(DS) >::proc( f, group, ap_el(IMPIXELSPACING), ps );
00848 if ( ps.size() > 0 )
00849 i.spacing_x_ = ps[0];
00850 else
00851 i.spacing_x_ = 0;
00852 if ( ps.size() > 1 )
00853 i.spacing_y_ = ps[1];
00854 else
00855 i.spacing_y_ = i.spacing_x_;
00856
00857 i.header_valid_ = true;
00858
00859 #undef ap_join
00860 #undef ap_type
00861 #undef ap_el
00862 }
00863
00864
00865
00866 namespace
00867 {
00868 template<class InT>
00869 void
00870 convert_src_type( InT const*,
00871 DcmPixelData* pixels,
00872 unsigned num_samples,
00873 Uint16 alloc,
00874 Uint16 stored,
00875 Uint16 high,
00876 Uint16 rep,
00877 DiInputPixel*& pixel_data,
00878 vil_pixel_format& act_format )
00879 {
00880 if ( rep == 0 && stored <= 8 ) {
00881 act_format = VIL_PIXEL_FORMAT_BYTE;
00882 pixel_data = new DiInputPixelTemplate<InT,Uint8>( pixels, alloc, stored, high, 0, num_samples );
00883 }
00884 else if ( rep == 0 && stored <= 16 ) {
00885 act_format = VIL_PIXEL_FORMAT_UINT_16;
00886 pixel_data = new DiInputPixelTemplate<InT,Uint16>( pixels, alloc, stored, high, 0, num_samples );
00887 }
00888 else if ( rep == 1 && stored <= 8 ) {
00889 act_format = VIL_PIXEL_FORMAT_SBYTE;
00890 pixel_data = new DiInputPixelTemplate<InT,Sint8>( pixels, alloc, stored, high, 0, num_samples );
00891 }
00892 else if ( rep == 1 && stored <= 16 ) {
00893 act_format = VIL_PIXEL_FORMAT_INT_16;
00894 pixel_data = new DiInputPixelTemplate<InT,Sint16>( pixels, alloc, stored, high, 0, num_samples );
00895 }
00896 }
00897
00898 template<class IntType, class OutType>
00899 void
00900 rescale_values( IntType const* int_begin,
00901 unsigned num_samples,
00902 OutType* float_begin,
00903 Float64 slope, Float64 intercept )
00904 {
00905 IntType const* const int_end = int_begin + num_samples;
00906 for ( ; int_begin != int_end; ++int_begin, ++float_begin ) {
00907 *float_begin = static_cast<OutType>( *int_begin * slope + intercept );
00908 }
00909 }
00910 }
00911 #ifdef MIXED_ENDIAN
00912 static unsigned short swap_short(unsigned short v)
00913 {
00914 return (v << 8)
00915 | (v >> 8);
00916 }
00917
00918 static void swap_shorts(unsigned short *ip, unsigned short *op, int count)
00919 {
00920 while (count)
00921 {
00922 *op++ = swap_short(*ip++);
00923 count--;
00924 }
00925 }
00926 #endif //MIXED_ENDIAN
00927 static
00928 void
00929 read_pixels_into_buffer(DcmPixelData* pixels,
00930 unsigned num_samples,
00931 Uint16 alloc,
00932 Uint16 stored,
00933 Uint16 high,
00934 Uint16 rep,
00935 Float64 slope,
00936 Float64 intercept,
00937 vil_memory_chunk_sptr& out_buf,
00938 vil_pixel_format& out_format)
00939 {
00940
00941
00942
00943
00944 vil_pixel_format act_format = VIL_PIXEL_FORMAT_UNKNOWN;
00945
00946
00947
00948
00949
00950 DiInputPixel* pixel_data = 0;
00951 if ( pixels->getVR() == EVR_OW ) {
00952 convert_src_type( (Uint16*)0, pixels, num_samples, alloc, stored, high, rep, pixel_data, act_format );
00953 }
00954 else {
00955 convert_src_type( (Uint8*)0, pixels, num_samples, alloc, stored, high, rep, pixel_data, act_format );
00956 }
00957 #ifdef MIXED_ENDIAN
00958 #ifdef NO_OFFSET
00959 slope = 1; intercept = 0;
00960 if (act_format == VIL_PIXEL_FORMAT_SBYTE)
00961 act_format = VIL_PIXEL_FORMAT_BYTE;
00962 if (act_format == VIL_PIXEL_FORMAT_INT_16)
00963 act_format = VIL_PIXEL_FORMAT_UINT_16;
00964 #endif //NO_OFFSET
00965 bool swap_data = false;
00966 unsigned short* temp1 = new unsigned short[num_samples];
00967 unsigned short* temp2 =
00968 reinterpret_cast<unsigned short*>(pixel_data->getData());
00969 swap_shorts(temp2, temp1, num_samples);
00970 vxl_byte* temp3 = reinterpret_cast<vxl_byte*>(temp1);
00971 #endif //MIXED_ENDIAN
00972
00973 if ( pixel_data == 0 ) {
00974 return;
00975 }
00976
00977
00978 pixels->clear();
00979
00980
00981
00982 if ( slope == 1 && intercept == 0 ) {
00983 out_format = act_format;
00984
00985
00986
00987
00988
00989
00990
00991
00992 out_buf = new vil_memory_chunk( num_samples * ((stored+7)/8), VIL_PIXEL_FORMAT_BYTE );
00993 #ifdef MIXED_ENDIAN
00994 vcl_memcpy( out_buf->data(), temp3, out_buf->size() );
00995 #else
00996 vcl_memcpy( out_buf->data(), pixel_data->getData(), out_buf->size() );
00997 #endif //MIXED_ENDIAN
00998 }
00999 else {
01000 out_buf = new vil_memory_chunk( num_samples * sizeof(float), VIL_PIXEL_FORMAT_FLOAT );
01001 out_format = VIL_PIXEL_FORMAT_FLOAT;
01002 #ifdef MIXED_ENDIAN
01003 void* in_begin = reinterpret_cast<void*>(temp1);
01004 #else
01005 void* in_begin = const_cast<void*>(pixel_data->getData());
01006 #endif //MIXED_ENDIAN
01007 float* out_begin = static_cast<float*>( out_buf->data() );
01008
01009 switch ( act_format )
01010 {
01011 case VIL_PIXEL_FORMAT_BYTE:
01012 rescale_values( (vxl_byte*)in_begin, num_samples, out_begin, slope, intercept );
01013 break;
01014 case VIL_PIXEL_FORMAT_SBYTE:
01015 rescale_values( (vxl_sbyte*)in_begin, num_samples, out_begin, slope, intercept );
01016 break;
01017 case VIL_PIXEL_FORMAT_UINT_16:
01018 rescale_values( (vxl_uint_16*)in_begin, num_samples, out_begin, slope, intercept );
01019 break;
01020 case VIL_PIXEL_FORMAT_INT_16:
01021 rescale_values( (vxl_sint_16*)in_begin, num_samples, out_begin, slope, intercept );
01022 break;
01023 default:
01024 vcl_cerr << "vil_dicom ERROR: unexpected internal pixel format\n";
01025 }
01026 }
01027
01028 #ifdef MIXED_ENDIAN
01029 delete [] temp1;
01030 #endif //MIXED_ENDIAN
01031
01032 delete pixel_data;
01033 }
01034
01035 #endif // HAS_DCMTK