comparison Core/DicomFormat/DicomIntegerPixelAccessor.cpp @ 368:80011cd589e6

support of rgb images
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 18 Feb 2013 16:07:28 +0100
parents 760d0f32cb34
children 4632a044746e
comparison
equal deleted inserted replaced
367:301f2831489c 368:80011cd589e6
38 38
39 #include "../OrthancException.h" 39 #include "../OrthancException.h"
40 #include <boost/lexical_cast.hpp> 40 #include <boost/lexical_cast.hpp>
41 #include <limits> 41 #include <limits>
42 #include <cassert> 42 #include <cassert>
43 #include <stdio.h>
43 44
44 namespace Orthanc 45 namespace Orthanc
45 { 46 {
46 static const DicomTag COLUMNS(0x0028, 0x0011); 47 static const DicomTag COLUMNS(0x0028, 0x0011);
47 static const DicomTag ROWS(0x0028, 0x0010); 48 static const DicomTag ROWS(0x0028, 0x0010);
48 static const DicomTag SAMPLES_PER_PIXEL(0x0028, 0x0002); 49 static const DicomTag SAMPLES_PER_PIXEL(0x0028, 0x0002);
49 static const DicomTag BITS_ALLOCATED(0x0028, 0x0100); 50 static const DicomTag BITS_ALLOCATED(0x0028, 0x0100);
50 static const DicomTag BITS_STORED(0x0028, 0x0101); 51 static const DicomTag BITS_STORED(0x0028, 0x0101);
51 static const DicomTag HIGH_BIT(0x0028, 0x0102); 52 static const DicomTag HIGH_BIT(0x0028, 0x0102);
52 static const DicomTag PIXEL_REPRESENTATION(0x0028, 0x0103); 53 static const DicomTag PIXEL_REPRESENTATION(0x0028, 0x0103);
54 static const DicomTag PLANAR_CONFIGURATION(0x0028, 0x0006);
53 55
54 DicomIntegerPixelAccessor::DicomIntegerPixelAccessor(const DicomMap& values, 56 DicomIntegerPixelAccessor::DicomIntegerPixelAccessor(const DicomMap& values,
55 const void* pixelData, 57 const void* pixelData,
56 size_t size) : 58 size_t size) :
57 pixelData_(pixelData), 59 pixelData_(pixelData),
59 { 61 {
60 unsigned int bitsAllocated; 62 unsigned int bitsAllocated;
61 unsigned int bitsStored; 63 unsigned int bitsStored;
62 unsigned int highBit; 64 unsigned int highBit;
63 unsigned int pixelRepresentation; 65 unsigned int pixelRepresentation;
66 planarConfiguration_ = 0;
64 67
65 try 68 try
66 { 69 {
67 width_ = boost::lexical_cast<unsigned int>(values.GetValue(COLUMNS).AsString()); 70 width_ = boost::lexical_cast<unsigned int>(values.GetValue(COLUMNS).AsString());
68 height_ = boost::lexical_cast<unsigned int>(values.GetValue(ROWS).AsString()); 71 height_ = boost::lexical_cast<unsigned int>(values.GetValue(ROWS).AsString());
69 samplesPerPixel_ = boost::lexical_cast<unsigned int>(values.GetValue(SAMPLES_PER_PIXEL).AsString()); 72 samplesPerPixel_ = boost::lexical_cast<unsigned int>(values.GetValue(SAMPLES_PER_PIXEL).AsString());
70 bitsAllocated = boost::lexical_cast<unsigned int>(values.GetValue(BITS_ALLOCATED).AsString()); 73 bitsAllocated = boost::lexical_cast<unsigned int>(values.GetValue(BITS_ALLOCATED).AsString());
71 bitsStored = boost::lexical_cast<unsigned int>(values.GetValue(BITS_STORED).AsString()); 74 bitsStored = boost::lexical_cast<unsigned int>(values.GetValue(BITS_STORED).AsString());
72 highBit = boost::lexical_cast<unsigned int>(values.GetValue(HIGH_BIT).AsString()); 75 highBit = boost::lexical_cast<unsigned int>(values.GetValue(HIGH_BIT).AsString());
73 pixelRepresentation = boost::lexical_cast<unsigned int>(values.GetValue(PIXEL_REPRESENTATION).AsString()); 76 pixelRepresentation = boost::lexical_cast<unsigned int>(values.GetValue(PIXEL_REPRESENTATION).AsString());
77
78 if (samplesPerPixel_ > 1)
79 {
80 // The "Planar Configuration" is only set when "Samples per Pixels" is greater than 1
81 // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.3/
82 planarConfiguration_ = boost::lexical_cast<unsigned int>(values.GetValue(PLANAR_CONFIGURATION).AsString());
83 }
74 } 84 }
75 catch (boost::bad_lexical_cast) 85 catch (boost::bad_lexical_cast)
86 {
87 throw OrthancException(ErrorCode_NotImplemented);
88 }
89 catch (OrthancException)
76 { 90 {
77 throw OrthancException(ErrorCode_NotImplemented); 91 throw OrthancException(ErrorCode_NotImplemented);
78 } 92 }
79 93
80 frame_ = 0; 94 frame_ = 0;
92 throw OrthancException(ErrorCode_NotImplemented); 106 throw OrthancException(ErrorCode_NotImplemented);
93 } 107 }
94 108
95 if ((bitsAllocated != 8 && bitsAllocated != 16 && 109 if ((bitsAllocated != 8 && bitsAllocated != 16 &&
96 bitsAllocated != 24 && bitsAllocated != 32) || 110 bitsAllocated != 24 && bitsAllocated != 32) ||
97 numberOfFrames_ == 0) 111 numberOfFrames_ == 0 ||
112 (planarConfiguration_ != 0 && planarConfiguration_ != 1))
98 { 113 {
99 throw OrthancException(ErrorCode_NotImplemented); 114 throw OrthancException(ErrorCode_NotImplemented);
100 } 115 }
101 116
102 if (bitsAllocated > 32 || 117 if (bitsAllocated > 32 ||
104 { 119 {
105 // Not available, as the accessor internally uses int32_t values 120 // Not available, as the accessor internally uses int32_t values
106 throw OrthancException(ErrorCode_NotImplemented); 121 throw OrthancException(ErrorCode_NotImplemented);
107 } 122 }
108 123
109 if (samplesPerPixel_ != 1) 124 if (samplesPerPixel_ != 1 &&
110 { 125 samplesPerPixel_ != 3)
111 throw OrthancException(ErrorCode_NotImplemented); 126 {
112 } 127 throw OrthancException(ErrorCode_NotImplemented);
113 128 }
114 if (width_ * height_ * bitsAllocated / 8 * numberOfFrames_ > size)
115 {
116 throw OrthancException(ErrorCode_BadFileFormat);
117 }
118
119 /*printf("%d %d %d %d %d %d %d %d\n", width_, height_, samplesPerPixel_, bitsAllocated,
120 bitsStored, highBit, pixelRepresentation, numberOfFrames_);*/
121 129
122 bytesPerPixel_ = bitsAllocated / 8; 130 bytesPerPixel_ = bitsAllocated / 8;
123 shift_ = highBit + 1 - bitsStored; 131 shift_ = highBit + 1 - bitsStored;
132 frameOffset_ = height_ * width_ * bytesPerPixel_ * samplesPerPixel_;
133
134 if (numberOfFrames_ * frameOffset_ > size)
135 {
136 throw OrthancException(ErrorCode_BadFileFormat);
137 }
138
139 /*printf("%d %d %d %d %d %d %d %d\n", width_, height_, samplesPerPixel_, bitsAllocated,
140 bitsStored, highBit, pixelRepresentation, numberOfFrames_);*/
124 141
125 if (pixelRepresentation) 142 if (pixelRepresentation)
126 { 143 {
127 mask_ = (1 << (bitsStored - 1)) - 1; 144 mask_ = (1 << (bitsStored - 1)) - 1;
128 signMask_ = (1 << (bitsStored - 1)); 145 signMask_ = (1 << (bitsStored - 1));
131 { 148 {
132 mask_ = (1 << bitsStored) - 1; 149 mask_ = (1 << bitsStored) - 1;
133 signMask_ = 0; 150 signMask_ = 0;
134 } 151 }
135 152
136 rowOffset_ = width_ * bytesPerPixel_; 153 if (planarConfiguration_ == 0)
137 frameOffset_ = height_ * width_ * bytesPerPixel_; 154 {
155 /**
156 * The sample values for the first pixel are followed by the
157 * sample values for the second pixel, etc. For RGB images, this
158 * means the order of the pixel values sent shall be R1, G1, B1,
159 * R2, G2, B2, ..., etc.
160 **/
161 rowOffset_ = width_ * bytesPerPixel_ * samplesPerPixel_;
162 }
163 else
164 {
165 /**
166 * Each color plane shall be sent contiguously. For RGB images,
167 * this means the order of the pixel values sent is R1, R2, R3,
168 * ..., G1, G2, G3, ..., B1, B2, B3, etc.
169 **/
170 rowOffset_ = width_ * bytesPerPixel_;
171 }
138 } 172 }
139 173
140 174
141 void DicomIntegerPixelAccessor::GetExtremeValues(int32_t& min, 175 void DicomIntegerPixelAccessor::GetExtremeValues(int32_t& min,
142 int32_t& max) const 176 int32_t& max) const
152 186
153 for (unsigned int y = 0; y < height_; y++) 187 for (unsigned int y = 0; y < height_; y++)
154 { 188 {
155 for (unsigned int x = 0; x < width_; x++) 189 for (unsigned int x = 0; x < width_; x++)
156 { 190 {
157 int32_t v = GetValue(x, y); 191 for (unsigned int c = 0; c < GetChannelCount(); c++)
158 if (v < min) 192 {
159 min = v; 193 int32_t v = GetValue(x, y);
160 if (v > max) 194 if (v < min)
161 max = v; 195 min = v;
196 if (v > max)
197 max = v;
198 }
162 } 199 }
163 } 200 }
164 } 201 }
165 202
166 203
167 int32_t DicomIntegerPixelAccessor::GetValue(unsigned int x, unsigned int y) const 204 int32_t DicomIntegerPixelAccessor::GetValue(unsigned int x,
168 { 205 unsigned int y,
169 assert(x < width_ && y < height_); 206 unsigned int channel) const
207 {
208 assert(x < width_ && y < height_ && channel < samplesPerPixel_);
170 209
171 const uint8_t* pixel = reinterpret_cast<const uint8_t*>(pixelData_) + 210 const uint8_t* pixel = reinterpret_cast<const uint8_t*>(pixelData_) +
172 y * rowOffset_ + x * bytesPerPixel_ + frame_ * frameOffset_; 211 y * rowOffset_ + frame_ * frameOffset_;
212
213 // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.3/
214 if (planarConfiguration_ == 0)
215 {
216 /**
217 * The sample values for the first pixel are followed by the
218 * sample values for the second pixel, etc. For RGB images, this
219 * means the order of the pixel values sent shall be R1, G1, B1,
220 * R2, G2, B2, ..., etc.
221 **/
222 pixel += channel * bytesPerPixel_ + x * samplesPerPixel_ * bytesPerPixel_;
223 }
224 else
225 {
226 /**
227 * Each color plane shall be sent contiguously. For RGB images,
228 * this means the order of the pixel values sent is R1, R2, R3,
229 * ..., G1, G2, G3, ..., B1, B2, B3, etc.
230 **/
231 assert(frameOffset_ % samplesPerPixel_ == 0);
232 pixel += channel * frameOffset_ / samplesPerPixel_ + x * bytesPerPixel_;
233 }
173 234
174 int32_t v; 235 int32_t v;
175 v = pixel[0]; 236 v = pixel[0];
176 if (bytesPerPixel_ >= 2) 237 if (bytesPerPixel_ >= 2)
177 v = v + (static_cast<int32_t>(pixel[1]) << 8); 238 v = v + (static_cast<int32_t>(pixel[1]) << 8);