]> Creatis software - gdcm.git/commitdiff
ENH: add code for segmented palette
authormalaterre <malaterre>
Wed, 3 Oct 2007 09:22:45 +0000 (09:22 +0000)
committermalaterre <malaterre>
Wed, 3 Oct 2007 09:22:45 +0000 (09:22 +0000)
src/gdcmSegmentedPalette.h [new file with mode: 0644]

diff --git a/src/gdcmSegmentedPalette.h b/src/gdcmSegmentedPalette.h
new file mode 100644 (file)
index 0000000..b9d20c5
--- /dev/null
@@ -0,0 +1,228 @@
+/*=========================================================================
+  Program:   gdcm
+  Module:    $RCSfile: gdcmSegmentedPalette.h,v $
+  Language:  C++
+  Date:      $Date: 2007/10/03 09:22:45 $
+  Version:   $Revision: 1.1 $
+                                                                                
+  Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
+  l'Image). All rights reserved. See Doc/License.txt or
+  http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
+                                                                                
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+                                                                                
+=========================================================================*/
+
+#include <gdcm.h>
+// Ref: 
+// http://blog.goo.ne.jp/satomi_takeo/e/3643e5249b2a9650f9e10ef1c830e8b8
+// I bet the code was compiled on VS6. Make it compile on other platform:
+// * typedef are not inherited
+// * need to explicitely add typename keyword
+// * Uint8 / Uint16 are neither C nor C++
+// * replace all dcmtk code with identical gdcm code
+
+#include <assert.h>
+#include <algorithm>
+#include <deque>
+#include <map>
+#include <vector>
+#include <iterator>
+
+namespace {
+    // abstract class for segment.
+    template <typename EntryType>
+    class Segment {
+    public:
+        typedef std::map<const EntryType*, const Segment*> SegmentMap;
+        virtual bool Expand(const SegmentMap& instances,
+            std::vector<EntryType>& expanded) const = 0;
+        const EntryType* First() const { return _first; }
+        const EntryType* Last() const { return _last; }
+        struct ToMap {
+            std::pair<
+                typename SegmentMap::key_type,
+                typename SegmentMap::mapped_type
+            >
+                operator()(const Segment* segment) const
+            { return std::make_pair(segment->First(), segment); }
+        };
+    protected:
+        Segment(const EntryType* first, const EntryType* last) {
+            _first = first; _last = last;
+        }
+        const EntryType* _first;
+        const EntryType* _last;
+    };
+
+    // discrete segment (opcode = 0)
+    template <typename EntryType>
+    class DiscreteSegment : public Segment<EntryType> {
+    public:
+        typedef typename Segment<EntryType>::SegmentMap SegmentMap;
+        DiscreteSegment(const EntryType* first)
+            : Segment<EntryType>(first, first+2+*(first+1)) {}
+        virtual bool Expand(const SegmentMap&,
+            std::vector<EntryType>& expanded) const
+        {
+            std::copy(this->_first + 2, this->_last, std::back_inserter(expanded));
+            return true;
+        }
+    };
+
+    // linear segment (opcode = 1)
+    template <typename EntryType>
+    class LinearSegment : public Segment<EntryType> {
+    public:
+        typedef typename Segment<EntryType>::SegmentMap SegmentMap;
+        LinearSegment(const EntryType* first)
+            : Segment<EntryType>(first, first+3) {}
+        virtual bool Expand(const SegmentMap&,
+            std::vector<EntryType>& expanded) const
+        {
+            if ( expanded.empty() ) {
+                // linear segment can't be the first segment.
+                return false;
+            }
+            EntryType length = *(this->_first + 1);
+            EntryType y0 = expanded.back();
+            EntryType y1 = *(this->_first + 2);
+            double y01 = y1 - y0;
+            for ( EntryType i = 0; i <length; ++i ) {
+                double value_float
+                    = static_cast<double>(y0)
+                    + (static_cast<double>(i)/static_cast<double>(length)) * y01;
+                EntryType value_int = static_cast<EntryType>(value_float + 0.5);
+                expanded.push_back(value_int);
+            }
+            return true;
+        }
+    };
+
+    // indirect segment (opcode = 2)
+    template <typename EntryType>
+    class IndirectSegment : public Segment<EntryType> {
+    public:
+        typedef typename Segment<EntryType>::SegmentMap SegmentMap;
+        IndirectSegment(const EntryType* first)
+            : Segment<EntryType>(first, first+2+4/sizeof(EntryType)) {}
+        virtual bool Expand(const SegmentMap& instances,
+            std::vector<EntryType>& expanded) const
+        {
+            if ( instances.empty() ) {
+                // some other segments are required as references.
+                return false;
+            }
+            const EntryType* first_segment = instances.begin()->first;
+            const unsigned short* pOffset
+                = reinterpret_cast<const unsigned short*>(this->_first + 2);
+            unsigned long offsetBytes
+                = (*pOffset) | (static_cast<unsigned long>(*(pOffset + 1)) << 16);
+            const EntryType* copied_part_head
+                = first_segment + offsetBytes / sizeof(EntryType);
+            typename SegmentMap::const_iterator ppHeadSeg = instances.find(copied_part_head);
+            if ( ppHeadSeg == instances.end() ) {
+                // referred segment not found
+                return false;
+            }
+            EntryType nNumCopies = *(this->_first + 1);
+            typename SegmentMap::const_iterator ppSeg = ppHeadSeg;
+            while ( std::distance(ppHeadSeg, ppSeg) <nNumCopies ) {
+                assert( ppSeg != instances.end() );
+                ppSeg->second->Expand(instances, expanded);
+                ++ppSeg;
+            }
+            return true;
+        }
+    };
+
+    template <typename EntryType>
+    void ExpandPalette(const EntryType* raw_values, uint32_t length,
+        std::vector<EntryType>& palette)
+    {
+        typedef std::deque<Segment<EntryType>*> SegmentList;
+        SegmentList segments;
+        const EntryType* raw_seg = raw_values;
+        while ( (std::distance(raw_values, raw_seg) * sizeof(EntryType)) <length ) {
+            Segment<EntryType>* segment = NULL;
+            if ( *raw_seg == 0 ) {
+                segment = new DiscreteSegment<EntryType>(raw_seg);
+            } else if ( *raw_seg == 1 ) {
+                segment = new LinearSegment<EntryType>(raw_seg);
+            } else if ( *raw_seg == 2 ) {
+                segment = new IndirectSegment<EntryType>(raw_seg);
+            }
+            if ( segment ) {
+                segments.push_back(segment);
+                raw_seg = segment->Last();
+            } else {
+                // invalid opcode
+                break;
+            }
+        }
+        typename Segment<EntryType>::SegmentMap instances;
+        std::transform(segments.begin(), segments.end(),
+            std::inserter(instances, instances.end()), typename Segment<EntryType>::ToMap());
+        typename SegmentList::iterator ppSeg = segments.begin();
+        typename SegmentList::iterator endOfSegments = segments.end();
+        for ( ; ppSeg != endOfSegments; ++ppSeg ) {
+            (*ppSeg)->Expand(instances, palette);
+        }
+        ppSeg = segments.begin();
+        for ( ; ppSeg != endOfSegments; ++ppSeg ) {
+            delete *ppSeg;
+        }
+    }
+
+    void ReadPalette(GDCM_NAME_SPACE::File* pds, const GDCM_NAME_SPACE::TagKey& descriptor,
+      const GDCM_NAME_SPACE::TagKey& segment)
+      {
+      int desc_values[3] = {};
+      unsigned long count = 0;
+      //if ( pds->findAndGetUint16Array(descriptor, desc_values, &count).good() )
+      std::string desc_values_str = pds->GetEntryString(descriptor.GetGroup(), descriptor.GetElement() );
+      count = sscanf( desc_values_str.c_str(), "%d\\%d\\%d", desc_values, desc_values+1, desc_values+2 );
+        {
+        assert( count == 3 );
+        unsigned int num_entries = desc_values[0];
+        if ( num_entries == 0 ) {
+          num_entries = 0x10000;
+        }
+        int min_pixel_value = desc_values[1];
+        unsigned int entry_size = desc_values[2];
+        assert( entry_size == 8 || entry_size == 16 );
+        //DcmElement* pe = NULL;
+        GDCM_NAME_SPACE::DataEntry* pe = NULL;
+
+        pe = pds->GetDataEntry(segment.GetGroup(), segment.GetElement() ); {
+          //if ( pds->findAndGetElement(segment, pe).good() )
+          unsigned long length = pe->GetLength();
+          if ( entry_size == 8 ) {
+            uint8_t* segment_values = NULL;
+            //if ( pe->getUint8Array(segment_values).good() )
+            segment_values = (uint8_t*)pe->GetBinArea(); {
+              std::vector<uint8_t> palette;
+              palette.reserve(num_entries);
+              ExpandPalette(segment_values, length, palette);
+            }
+          } else if ( entry_size == 16 ) {
+            uint16_t* segment_values = NULL;
+            segment_values = (uint16_t*)pe->GetBinArea(); {
+              //if ( pe->getUint16Array(segment_values).good() )
+              std::vector<uint16_t> palette;
+              palette.reserve(num_entries);
+              ExpandPalette(segment_values, length, palette);
+//              std::copy(palette.begin(), palette.end(), 
+//                std::ostream_iterator<uint16_t>(std::cout, "\n"));
+
+            }
+          }
+        }
+        }
+      }
+} // end namespace
+
+