1 /* 2 * 3 * Copyright (C) 2002-2016, OFFIS e.V. 4 * All rights reserved. See COPYRIGHT file for details. 5 * 6 * This software and supporting documentation were developed by 7 * 8 * OFFIS e.V. 9 * R&D Division Health 10 * Escherweg 2 11 * D-26121 Oldenburg, Germany 12 * 13 * 14 * Module: dcmimage 15 * 16 * Author: Marco Eichelberg 17 * 18 * Purpose: class DcmQuantColorTable 19 * 20 */ 21 22 23 #ifndef DIQTCTAB_H 24 #define DIQTCTAB_H 25 26 #include "dcmtk/config/osconfig.h" 27 #include "dcmtk/ofstd/oftypes.h" /* for OFBool */ 28 #include "dcmtk/ofstd/ofcond.h" /* for OFCondition */ 29 #include "dcmtk/dcmimage/diqtpix.h" /* for DcmQuantPixel */ 30 #include "dcmtk/dcmimage/diqthash.h" /* for DcmQuantHistogramItem */ 31 #include "dcmtk/ofstd/ofstring.h" /* for class OFString */ 32 33 34 class DicomImage; 35 class DcmItem; 36 37 38 /** this class implements a color table that can either be 39 * a look-up table or an image color histogram. 40 */ 41 class DCMTK_DCMIMAGE_EXPORT DcmQuantColorTable 42 { 43 public: 44 45 /// constructor 46 DcmQuantColorTable(); 47 48 /// destructor 49 ~DcmQuantColorTable(); 50 51 /// resets the object to default-constructed state 52 void clear(); 53 54 /** returns the number of colors in the color table 55 * @return number of colors in color table 56 */ getColors()57 inline unsigned long getColors() const 58 { 59 return numColors; 60 } 61 62 /** creates a description string suitable for use as 63 * Derivation Description. 64 * @param str description string returned in this parameter 65 */ 66 void setDescriptionString(OFString& str) const; 67 68 /** creates a color table containing a histogram of the given 69 * image. Pixel sample values are downsampled if necessary 70 * to make sure the histogram fits into the given size limit. 71 * @param image color image for which a histogram is computed 72 * @param maxcolors maximum number of colors allowed in histogram. 73 * If necessary, pixel sample values are down-sampled to enforce 74 * this maximum. 75 * @return EC_Normal if successful, an error code otherwise. 76 */ 77 OFCondition computeHistogram(DicomImage& image, unsigned long maxcolors); 78 79 /** after a call to computeHistogram(), this method 80 * returns the maximum pixel value to which all color samples 81 * were down-sampled during computation of the histogram. 82 */ getMaxVal()83 inline unsigned long getMaxVal() const 84 { 85 return maxval; 86 } 87 88 /** returns the color at index idx. 89 * @param idx index, must be < getColors() 90 * @return const reference to color 91 */ getPixel(unsigned long idx)92 inline const DcmQuantPixel& getPixel(unsigned long idx) const 93 { 94 #ifdef DEBUG 95 assert(array && idx < numColors); 96 #endif 97 return *(array[idx]); 98 } 99 100 /** returns the red color component at index idx 101 * @param idx index, must be < getColors() 102 * @return red color component 103 */ getRed(unsigned long idx)104 inline DcmQuantComponent getRed(unsigned long idx) const 105 { 106 #ifdef DEBUG 107 assert(array && idx < numColors); 108 #endif 109 return array[idx]->getRed(); 110 } 111 112 /** returns the green color component at index idx 113 * @param idx index, must be < getColors() 114 * @return green color component 115 */ getGreen(unsigned long idx)116 inline DcmQuantComponent getGreen(unsigned long idx) const 117 { 118 #ifdef DEBUG 119 assert(array && idx < numColors); 120 #endif 121 return array[idx]->getGreen(); 122 } 123 124 /** returns the blue color component at index idx 125 * @param idx index, must be < getColors() 126 * @return blue color component 127 */ getBlue(unsigned long idx)128 inline DcmQuantComponent getBlue(unsigned long idx) const 129 { 130 #ifdef DEBUG 131 assert(array && idx < numColors); 132 #endif 133 return array[idx]->getBlue(); 134 } 135 136 /** computes a color LUT for the given image histogram. 137 * This median-cut colormap generator is based 138 * on Paul Heckbert's paper "Color Image Quantization for Frame Buffer 139 * Display", SIGGRAPH '82 Proceedings, page 297. 140 * @param histogram image color histogram 141 * @param sum number of pixels in image (colums * rows * frames) 142 * @param theMaxval maximum value to which pixels were 143 * downsampled for histogram computation 144 * @param numberOfColors desired number of colors in color LUT 145 * @param largeType algorithm used for determining the largest dimension 146 * in the Median Cut algorithm 147 * @param repType algorithm for choosing a representative color for each 148 * box in the Median Cut algorithm 149 * @return EC_Normal if successful, an error code otherwise. 150 */ 151 OFCondition medianCut( 152 DcmQuantColorTable& histogram, 153 unsigned long sum, 154 unsigned long theMaxval, 155 unsigned long numberOfColors, 156 DcmLargestDimensionType largeType, 157 DcmRepresentativeColorType repType); 158 159 /** determines for a given color the closest match in the color LUT. 160 * @param px color to look up in LUT 161 * @return index of closest match in LUT, -1 if look-up table empty 162 */ computeIndex(const DcmQuantPixel & px)163 inline int computeIndex(const DcmQuantPixel& px) const 164 { 165 int result = -1; 166 int r2, g2, b2; 167 long newdist; 168 int r1 = OFstatic_cast(int, px.getRed()); 169 int g1 = OFstatic_cast(int, px.getGreen()); 170 int b1 = OFstatic_cast(int, px.getBlue()); 171 long dist = 2000000000; 172 for (unsigned long i = 0; i < numColors; ++i) 173 { 174 r2 = r1 - OFstatic_cast(int, array[i]->getRed()); 175 g2 = g1 - OFstatic_cast(int, array[i]->getGreen()); 176 b2 = b1 - OFstatic_cast(int, array[i]->getBlue()); 177 newdist = r2*r2 + g2*g2 + b2*b2; 178 if (newdist < dist) 179 { 180 result = OFstatic_cast(int, i); 181 dist = newdist; 182 if (dist < array[i]->getValue()) i=numColors; // break out of for loop 183 } 184 } 185 return result; 186 } 187 188 /** writes the current color table into a DICOM object, encoded as 189 * Red/Green/Blue Palette Color Lookup Table and Data. 190 * @param target DICOM dataset to write to 191 * @param writeAsOW if true, LUT data is encoded as OW, otherwise LUT data 192 * is encoded as US. A LUT with 64k entries is always encoded as OW since 193 * a US data element with 64k entries cannot be written in explicit VR. 194 * @param write16BitEntries if true, LUT data is encoded with 16 bits per entry 195 * @return EC_Normal if successful, an error code otherwise. 196 */ 197 OFCondition write( 198 DcmItem& target, 199 OFBool writeAsOW, 200 OFBool write16BitEntries); 201 202 203 private: 204 205 /** after a call to medianCut(), this method computes for each entry in 206 * the color map the minimum of the euclidean distances to any other 207 * of the entries. Any color which has an euclidean distance of less 208 * than half of this distance is necessarily mapped to this entry. 209 * This data is used by computeIndex() 210 */ 211 void computeClusters(); 212 213 /// private undefined copy constructor 214 DcmQuantColorTable(const DcmQuantColorTable& src); 215 216 /// private undefined copy assignment operator 217 DcmQuantColorTable& operator=(const DcmQuantColorTable& src); 218 219 /// color table data 220 DcmQuantHistogramItemPointer *array; 221 222 /// number of entries in color table 223 unsigned long numColors; 224 225 /** maximum pixel value to which all color samples 226 * were down-sampled during computation of the histogram. 227 */ 228 unsigned long maxval; 229 230 }; 231 232 #endif 233