Mercurial > hg > orthanc
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); |