# Visualization Library

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

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

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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

Go to the documentation of this file.

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

Visualization Library v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:30.
Permission is granted to use this page to write and publish articles regarding Visualization Library.