# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlCore/plugins/vlDICOM.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.com                                               */
    00005 /*                                                                                    */
    00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
    00007 /*  All rights reserved.                                                              */
    00008 /*                                                                                    */
    00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
    00010 /*  are permitted provided that the following conditions are met:                     */
    00011 /*                                                                                    */
    00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
    00013 /*  list of conditions and the following disclaimer.                                  */
    00014 /*                                                                                    */
    00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
    00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
    00017 /*  other materials provided with the distribution.                                   */
    00018 /*                                                                                    */
    00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
    00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
    00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
    00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
    00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
    00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
    00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
    00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
    00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
    00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
    00029 /*                                                                                    */
    00030 /**************************************************************************************/
    00031
    00032 #ifndef vlDICOM_INCLUDE_ONCE
    00033 #define vlDICOM_INCLUDE_ONCE
    00034
    00035 #include "vlDICOM.hpp"
    00036 #include <vlCore/LoadWriterManager.hpp>
    00037 #include <vlCore/FileSystem.hpp>
    00038 #include <vlCore/GLSLmath.hpp>
    00039
    00040 #include <gdcmReader.h>
    00041 #include <gdcmWriter.h>
    00042 #include <gdcmAttribute.h>
    00043 #include <gdcmImageReader.h>
    00044 #include <gdcmImageWriter.h>
    00045 #include <gdcmImage.h>
    00046 #include <gdcmPhotometricInterpretation.h>
    00047 #include <gdcmImage.h>
    00048 #include <gdcmImageWriter.h>
    00049
    00050 #include <memory>
    00051
    00052 using namespace vl;
    00053
    00054 //---------------------------------------------------------------------------
    00055 static void to8bits(int bits_used, void* ptr, int px_count, bool reverse)
    00056 {
    00057   unsigned char* px = (unsigned char*)ptr;
    00058   if (bits_used >= 8)
    00059     return;
    00060   unsigned int max1 = (1<<bits_used)-1;
    00061   unsigned int max2 = 0xFF;
    00062   for(int i=0; i<px_count; ++i)
    00063     if (reverse)
    00064       px[i] = 0xFF - (unsigned char)( (float)px[i]/max1*max2 );
    00065     else
    00066       px[i] = (unsigned char)( (float)px[i]/max1*max2 );
    00067 }
    00068 static void to16bits(int bits_used, void* ptr, int px_count, bool reverse)
    00069 {
    00070   unsigned short* px = (unsigned short*)ptr;
    00071
    00072   if (bits_used >= 16)
    00073     return;
    00074   unsigned int max1 = (1<<bits_used)-1;
    00075   unsigned int max2 = 0xFFFF;
    00076   for(int i=0; i<px_count; ++i)
    00077   {
    00078     if (reverse)
    00079       px[i] = 0xFFFF - (unsigned short)( (float)px[i]/max1*max2 );
    00080     else
    00081       px[i] = (unsigned short)( (float)px[i]/max1*max2 );
    00082   }
    00083 }
    00084 static void to32bits(int bits_used, void* ptr, int px_count, bool reverse)
    00085 {
    00086   unsigned int* px = (unsigned int*)ptr;
    00087   if (bits_used >= 32)
    00088     return;
    00089   unsigned int max1 = (1<<bits_used)-1;
    00090   unsigned int max2 = 0xFFFFFFFF;
    00091   for(int i=0; i<px_count; ++i)
    00092     if (reverse)
    00093       px[i] = 0xFFFFFFFF - (unsigned int)( (float)px[i]/max1*max2 );
    00094     else
    00095       px[i] = (unsigned int)( (float)px[i]/max1*max2 );
    00096 }
    00097 //-----------------------------------------------------------------------------
    00098 ref<Image> vl::loadDICOM(const String& path)
    00099 {
    00100   ref<VirtualFile> file = defFileSystem()->locateFile(path);
    00101   if ( !file )
    00102   {
    00103     Log::error( Say("File '%s' not found.\n") << path );
    00104     return NULL;
    00105   }
    00106   else
    00107     return loadDICOM(file.get());
    00108 }
    00109 //-----------------------------------------------------------------------------
    00111 ref<Image> vl::loadDICOM(VirtualFile* vfile)
    00112 {
    00113   gdcm::ImageReader reader;
    00114
    00115   if (!vfile->open(OM_ReadOnly))
    00116   {
    00117     Log::error( Say("loadDICOM: cannot open file '%s'\n") << vfile->path() );
    00118     return NULL;
    00119   }
    00120
    00121   const int bufsize = 128*1024;
    00122   char buffer[bufsize];
    00123   long long count = 0;
    00124   std::stringstream strstr;
    00125   while( (count=vfile->read(buffer, bufsize)) )
    00126     strstr.write(buffer,(int)count);
    00127   std::istream* istr = &strstr;
    00128   reader.SetStream( *istr );
    00129   if( !reader.Read() )
    00130   {
    00131     std::cerr << "Could not read: " << vfile->path().toStdString() << std::endl;
    00132     vfile->close();
    00133     return NULL;
    00134   }
    00135
    00136   gdcm::File &file = reader.GetFile();
    00137   const gdcm::Image &image = reader.GetImage();
    00138
    00139   #if 0
    00140     printf("GDCM --- --- --- --- ---\n");
    00141     image.Print(std::cout);
    00142   #endif
    00143
    00144   unsigned int ndim = image.GetNumberOfDimensions();
    00145   const unsigned int *dims = image.GetDimensions();
    00146   gdcm::PixelFormat pf = image.GetPixelFormat();
    00147   const gdcm::PhotometricInterpretation &pi = image.GetPhotometricInterpretation();
    00148
    00149   /* for debugging purposes only
    00150   const double *origin = image.GetOrigin();
    00151   unsigned int planar_conf = image.GetPlanarConfiguration();
    00152   unsigned int rows = image.GetRows();
    00153   unsigned int cols = image.GetColumns();
    00154   unsigned int buflen = image.GetBufferLength();
    00155   int swap = image.GetNeedByteSwap();
    00156   int overlays = image.GetNumberOfOverlays();
    00157   */
    00158
    00159   ref<KeyValues> tags = new KeyValues;
    00160   tags->set("Origin")    = Say("%n %n %n") << image.GetOrigin()[0]  << image.GetOrigin()[1]  << image.GetOrigin()[2];
    00161   tags->set("Spacing")   = Say("%n %n %n") << image.GetSpacing()[0] << image.GetSpacing()[1] << image.GetSpacing()[2];
    00162   tags->set("Intercept") = Say("%n") << image.GetIntercept();
    00163   tags->set("Slope")     = Say("%n") << image.GetSlope();
    00164   tags->set("DirectionCosines") = Say("%n %n %n %n %n %n")
    00165                                   << image.GetDirectionCosines()[0] << image.GetDirectionCosines()[1] << image.GetDirectionCosines()[2]
    00166                                   << image.GetDirectionCosines()[3] << image.GetDirectionCosines()[4] << image.GetDirectionCosines()[5];
    00167   tags->set("BitsStored") = Say("%n") << pf.GetBitsStored();
    00168
    00169   gdcm::DataSet& ds = file.GetDataSet();
    00170
    00171   {
    00172     gdcm::Attribute<0x28,0x1050> win_center;
    00173     const gdcm::DataElement& de = ds.GetDataElement( win_center.GetTag() );
    00174     if(!de.IsEmpty())
    00175     {
    00176       win_center.SetFromDataElement( ds.GetDataElement( win_center.GetTag() ) );
    00177       tags->set("WindowCenter") = Say("%n") << win_center.GetValue();
    00178     }
    00179   }
    00180
    00181   {
    00182     gdcm::Attribute<0x28,0x1051> win_width;
    00183     const gdcm::DataElement& de = ds.GetDataElement( win_width.GetTag() );
    00184     if(!de.IsEmpty())
    00185     {
    00186       win_width.SetFromDataElement( ds.GetDataElement( win_width.GetTag() ) );
    00187       tags->set("WindowWidth") = Say("%n") << win_width.GetValue();
    00188     }
    00189   }
    00190
    00191   {
    00192     gdcm::Attribute<0x28,0x1052> rescale_intercept;
    00193     const gdcm::DataElement& de = ds.GetDataElement( rescale_intercept.GetTag() );
    00194     if(!de.IsEmpty())
    00195     {
    00196       rescale_intercept.SetFromDataElement( ds.GetDataElement( rescale_intercept.GetTag() ) );
    00197       tags->set("RescaleIntercept") = Say("%n") << rescale_intercept.GetValue();
    00198     }
    00199     else
    00200       tags->set("RescaleIntercept") = Say("%n") << 0;
    00201   }
    00202
    00203   {
    00204     gdcm::Attribute<0x28,0x1053> rescale_slope;
    00205     const gdcm::DataElement& de = ds.GetDataElement( rescale_slope.GetTag() );
    00206     if(!de.IsEmpty())
    00207     {
    00208       rescale_slope.SetFromDataElement( ds.GetDataElement( rescale_slope.GetTag() ) );
    00209       tags->set("RescaleSlope") = Say("%n") << rescale_slope.GetValue();
    00210     }
    00211     else
    00212       tags->set("RescaleIRescaleSlopentercept") = Say("%n") << 1;
    00213   }
    00214
    00215   #if 0
    00216     printf("TAGS --- --- --- --- ---\n");
    00217     tags->print();
    00218   #endif
    00219
    00220   int w=1,h=1,d=1;
    00221   if (ndim>=1)
    00222     w = dims[0];
    00223   if (ndim>=2)
    00224     h = dims[1];
    00225   if (ndim>=3)
    00226     d = dims[2];
    00227   h = h * d;
    00228
    00229   ref<Image> img = new Image;
    00230   img->setObjectName( vfile->path().toStdString() );
    00231   if (pf.GetSamplesPerPixel() == 1 && pi == gdcm::PhotometricInterpretation::PALETTE_COLOR)
    00232   {
    00233     if (pf.GetBitsStored() <= 8)
    00234     {
    00235       img->allocate2D( w, h, 1, vl::IF_RGBA, vl::IT_UNSIGNED_BYTE);
    00236       image.GetBuffer((char*)img->pixels());
    00237
    00238       const gdcm::LookupTable& lut = image.GetLUT();
    00239       std::auto_ptr<char> rgba( new char[(1<<lut.GetBitSample())*4] );
    00240       lut.GetBufferAsRGBA((unsigned char*)rgba.get());
    00241       for(int i=w*h; i--; )
    00242       {
    00243         int idx = img->pixels()[i];
    00244         img->pixels()[i*4+0] = rgba.get()[idx*4+0];
    00245         img->pixels()[i*4+1] = rgba.get()[idx*4+1];
    00246         img->pixels()[i*4+2] = rgba.get()[idx*4+2];
    00247         img->pixels()[i*4+3] = rgba.get()[idx*4+3];
    00248       }
    00249     }
    00250     else
    00251     if (pf.GetBitsStored() <= 16)
    00252     {
    00253       img->allocate2D( w, h, 1, vl::IF_RGBA, vl::IT_UNSIGNED_BYTE);
    00254       image.GetBuffer((char*)img->pixels());
    00255
    00256       const gdcm::LookupTable& lut = image.GetLUT();
    00257       std::auto_ptr<char> rgba( new char[(1<<lut.GetBitSample())*4] );
    00258       lut.GetBufferAsRGBA((unsigned char*)rgba.get());
    00259       for(int i=w*h; i--; )
    00260       {
    00261         int idx = ((unsigned short*)img->pixels())[i];
    00262         img->pixels()[i*4+0] = rgba.get()[idx*4+0];
    00263         img->pixels()[i*4+1] = rgba.get()[idx*4+1];
    00264         img->pixels()[i*4+2] = rgba.get()[idx*4+2];
    00265         img->pixels()[i*4+3] = rgba.get()[idx*4+3];
    00266       }
    00267     }
    00268   }
    00269   else
    00270   if (pf.GetSamplesPerPixel() == 1 && (pi == gdcm::PhotometricInterpretation::MONOCHROME2 || pi == gdcm::PhotometricInterpretation::MONOCHROME1))
    00271   {
    00272     if (pf.GetBitsStored() <= 8)
    00273     {
    00274       img->allocate2D( w, h, 1, vl::IF_LUMINANCE, vl::IT_UNSIGNED_BYTE);
    00275       image.GetBuffer((char*)img->pixels());
    00276       if (pi == gdcm::PhotometricInterpretation::MONOCHROME1)
    00277         to8bits(pf.GetBitsStored(), img->pixels(), w*h, true);
    00278       else
    00279         to8bits(pf.GetBitsStored(), img->pixels(), w*h, false);
    00280     }
    00281     else
    00282     if (pf.GetBitsStored() <= 16)
    00283     {
    00284       img->allocate2D( w, h, 1, vl::IF_LUMINANCE, vl::IT_UNSIGNED_SHORT);
    00285       image.GetBuffer((char*)img->pixels());
    00286       if (pi == gdcm::PhotometricInterpretation::MONOCHROME1)
    00287         to16bits(pf.GetBitsStored(), img->pixels(), w*h, true);
    00288       else
    00289         to16bits(pf.GetBitsStored(), img->pixels(), w*h, false);
    00290     }
    00291     else
    00292     if (pf.GetBitsStored() <= 32)
    00293     {
    00294       img->allocate2D( w, h, 1, vl::IF_LUMINANCE, vl::IT_UNSIGNED_INT);
    00295       image.GetBuffer((char*)img->pixels());
    00296       if (pi == gdcm::PhotometricInterpretation::MONOCHROME1)
    00297         to32bits(pf.GetBitsStored(), img->pixels(), w*h, true);
    00298       else
    00299         to32bits(pf.GetBitsStored(), img->pixels(), w*h, false);
    00300     }
    00301   }
    00302   else
    00303   if (pf.GetSamplesPerPixel() == 3)
    00304   {
    00305     if (pf.GetBitsStored() <= 8)
    00306     {
    00307       img->allocate2D( w, h, 1, vl::IF_RGB, vl::IT_UNSIGNED_BYTE);
    00308       image.GetBuffer((char*)img->pixels());
    00309       if (image.GetPlanarConfiguration())
    00310       {
    00311         int slice_pix_count = w*h/d;
    00312         std::auto_ptr<char> px ( new char[slice_pix_count*3] );
    00313         for(int slice=0; slice<d; ++slice)
    00314         {
    00315           char* red   = (char* )img->pixels() + slice*slice_pix_count*3 + 0;
    00316           char* green = (char* )img->pixels() + slice*slice_pix_count*3 + slice_pix_count;
    00317           char* blue  = (char* )img->pixels() + slice*slice_pix_count*3 + slice_pix_count*2;
    00318           for(int i=0; i<slice_pix_count*3; i+=3, ++red, ++green, ++blue)
    00319           {
    00320             px.get()[i+0] = *red;
    00321             px.get()[i+1] = *green;
    00322             px.get()[i+2] = *blue;
    00323           }
    00324           memcpy(img->pixels(), px.get(), img->requiredMemory());
    00325         }
    00326       }
    00327     }
    00328     else
    00329     if (pf.GetBitsStored() <= 16)
    00330     {
    00331       img->allocate2D( w, h, 1, vl::IF_RGB, vl::IT_UNSIGNED_SHORT);
    00332       image.GetBuffer((char*)img->pixels());
    00333       if (image.GetPlanarConfiguration())
    00334       {
    00335         int slice_pix_count = w*h/d;
    00336         std::auto_ptr<short> px ( new short[slice_pix_count*3] );
    00337         for(int slice=0; slice<d; ++slice)
    00338         {
    00339           short* red   = (short* )img->pixels() + slice*slice_pix_count*3 + 0;
    00340           short* green = (short* )img->pixels() + slice*slice_pix_count*3 + slice_pix_count;
    00341           short* blue  = (short* )img->pixels() + slice*slice_pix_count*3 + slice_pix_count*2;
    00342           for(int i=0; i<slice_pix_count*3; i+=3, ++red, ++green, ++blue)
    00343           {
    00344             px.get()[i+0] = *red;
    00345             px.get()[i+1] = *green;
    00346             px.get()[i+2] = *blue;
    00347           }
    00348           memcpy(img->pixels(), px.get(), img->requiredMemory());
    00349         }
    00350       }
    00351     }
    00352     else
    00353     {
    00354       vl::Log::error("DICOM format not supported: SamplesPerPixel = 3, BitsStored > 16.\n\n");
    00355       image.Print(std::cout);
    00356       vfile->close();
    00357       return NULL;
    00358     }
    00359   }
    00360   else
    00361   {
    00362     vl::Log::error("DICOM format not supported.\n");
    00363     image.Print(std::cout);
    00364     vfile->close();
    00365     return NULL;
    00366   }
    00367   vfile->close();
    00368   img->setHeight(h/d);
    00369   img->setDepth(d>1?d:0);
    00370   img->setTags(tags.get());
    00371   img->flipVertically();
    00372   return img;
    00373 }
    00374 //---------------------------------------------------------------------------
    00375 bool vl::isDICOM(VirtualFile* file)
    00376 {
    00377   file->open(OM_ReadOnly);
    00378   file->seekSet(128);
    00379   char signature[] = { 'D', 'I', 'C', 'M' };
    00380   char buf[]       = { 0,   0,   0,   0   };
    00381   file->read(buf,4);
    00382   bool ok = memcmp(buf,signature,4) == 0;
    00383   file->close();
    00384   return ok;
    00385 }
    00386 //---------------------------------------------------------------------------
    00387 bool vl::saveDICOM(const Image* src, const String& path)
    00388 {
    00389   return saveDICOM(src, new DiskFile(path));
    00390 }
    00391 //-----------------------------------------------------------------------------
    00392 bool vl::saveDICOM(const Image* src, VirtualFile* fout)
    00393 {
    00394   if (src->dimension()<1 || src->dimension()>3)
    00395   {
    00396     vl::Log::error("saveDICOM(): uncompatible image dimension().\n");
    00397     return false;
    00398   }
    00399
    00400   ref<Image> img = new Image;
    00401   *img = *src;
    00402
    00403   // bytes per sample
    00404   unsigned short bps = 0;
    00405   switch(img->type())
    00406   {
    00407   case vl::IT_UNSIGNED_BYTE:  bps = 1; break;
    00408   case vl::IT_UNSIGNED_SHORT: bps = 2; break;
    00409   default:
    00410     vl::Log::error("saveDICOM(): unsupported image type().\n");
    00411     return false;
    00412   }
    00413
    00414   // sample count;
    00415   unsigned short spp = 0;
    00416   switch(img->format())
    00417   {
    00418     case vl::IF_ALPHA:     spp = 1; break;
    00419     case vl::IF_LUMINANCE: spp = 1; break;
    00420     case vl::IF_LUMINANCE_ALPHA: spp = 1; break; // converted to IF_LUMINANCE
    00421     case vl::IF_RGB:  spp = 3; break;
    00422     case vl::IF_BGR:  spp = 3; break; // converted to IF_RGB
    00423     case vl::IF_RGBA: spp = 3; break; // converted to IF_RGB
    00424     case vl::IF_BGRA: spp = 3; break; // converted to IF_RGB
    00425     default:
    00426       vl::Log::error("saveDICOM(): unsupported image format().\n");
    00427       return false;
    00428   }
    00429
    00430   if (img->format() == vl::IF_LUMINANCE_ALPHA)
    00431     img = img->convertFormat(vl::IF_LUMINANCE);
    00432   if (img->format() == vl::IF_BGR)
    00433     img = img->convertFormat(vl::IF_RGB);
    00434   if (img->format() == vl::IF_BGRA || img->format() == vl::IF_RGBA)
    00435     img = img->convertFormat(vl::IF_RGB);
    00436
    00437   gdcm::SmartPointer<gdcm::Image> im = new gdcm::Image;
    00438   im->SetNumberOfDimensions( img->dimension() );
    00439   int dims[] = { img->width(), img->height()?img->height():1, img->depth()?img->depth():1 };
    00440   for(int i=0; i<img->dimension(); ++i)
    00441     im->SetDimension( i, dims[i] );
    00442
    00443   im->GetPixelFormat().SetScalarType(bps==8?gdcm::PixelFormat::INT8:gdcm::PixelFormat::INT16);
    00444   im->GetPixelFormat().SetBitsAllocated(bps*8);
    00445   im->GetPixelFormat().SetBitsStored(bps*8);
    00446   im->GetPixelFormat().SetHighBit(bps*8-1);
    00447   im->GetPixelFormat().SetSamplesPerPixel(spp);
    00448   gdcm::PhotometricInterpretation pi = spp==1?gdcm::PhotometricInterpretation::MONOCHROME2:gdcm::PhotometricInterpretation::RGB;
    00449   im->SetPhotometricInterpretation(pi);
    00450   // im->SetTransferSyntax(gdcm::TransferSyntax::JPEGBaselineProcess1);
    00451
    00452   unsigned long len = im->GetBufferLength();
    00453   unsigned long req = img->requiredMemory();
    00454   if( len != req )
    00455   {
    00456     // is a img->byteAlignment() issue?
    00457     vl::Log::error("saveDICOM(): buffer size computation error.\n");
    00458     VL_TRAP()
    00459     return false;
    00460   }
    00461
    00462   img->flipVertically();
    00463
    00464   gdcm::DataElement pixeldata( gdcm::Tag(0x7fe0,0x0010) );
    00465   pixeldata.SetByteValue( (const char*)img->pixels(), len );
    00466   im->SetDataElement( pixeldata );
    00467
    00468   gdcm::ImageWriter w;
    00469   w.SetImage( *im );
    00470   std::ostringstream ostr;
    00471   w.SetStream(ostr);
    00472   if( !w.Write() )
    00473   {
    00474     vl::Log::error("saveDICOM(): error writing stream.\n");
    00475     return false;
    00476   }
    00477   fout->open(OM_WriteOnly);
    00478   int bcount = (int)fout->write(ostr.str().c_str(), ostr.str().length());
    00479   fout->close();
    00480   if( bcount != (int)ostr.str().length() )
    00481   {
    00482     vl::Log::error("saveDICOM(): error writing file.\n");
    00483     return false;
    00484   }
    00485
    00486   return true;
    00487 }
    00488
    00489 #endif

Visualization Library v2011.05.1142 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 26 2011 22:51:21.
Permission is granted to use this page to write and publish articles regarding Visualization Library.