Mercurial > hg > orthanc
comparison OrthancFramework/Sources/DicomFormat/DicomIntegerPixelAccessor.cpp @ 4827:4cfd96732076
Support decoding of black-and-white images (with 1 bit per pixel), notably DICOM SEG
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 25 Nov 2021 15:52:54 +0100 |
parents | 381c2ca04860 |
children | 7053502fbf97 |
comparison
equal
deleted
inserted
replaced
4825:381c2ca04860 | 4827:4cfd96732076 |
---|---|
86 * The sample values for the first pixel are followed by the | 86 * The sample values for the first pixel are followed by the |
87 * sample values for the second pixel, etc. For RGB images, this | 87 * sample values for the second pixel, etc. For RGB images, this |
88 * means the order of the pixel values sent shall be R1, G1, B1, | 88 * means the order of the pixel values sent shall be R1, G1, B1, |
89 * R2, G2, B2, ..., etc. | 89 * R2, G2, B2, ..., etc. |
90 **/ | 90 **/ |
91 rowOffset_ = information_.GetWidth() * information_.GetBytesPerValue() * information_.GetChannelCount(); | 91 if (information_.GetBitsStored() == 1) |
92 { | |
93 if (information_.GetChannelCount() == 1 && | |
94 information_.GetBitsAllocated() == 1) | |
95 { | |
96 assert(information_.GetWidth() % 8 == 0); // Tested by DicomImageInformation | |
97 rowOffset_ = information_.GetWidth() / 8; | |
98 } | |
99 else | |
100 { | |
101 throw OrthancException(ErrorCode_IncompatibleImageFormat, | |
102 "Image not supported (multi-channel black-and-image image)"); | |
103 } | |
104 } | |
105 else | |
106 { | |
107 rowOffset_ = information_.GetWidth() * information_.GetBytesPerValue() * information_.GetChannelCount(); | |
108 } | |
92 } | 109 } |
93 } | 110 } |
94 | 111 |
95 | 112 |
96 void DicomIntegerPixelAccessor::GetExtremeValues(int32_t& min, | 113 void DicomIntegerPixelAccessor::GetExtremeValues(int32_t& min, |
131 unsigned int channel) const | 148 unsigned int channel) const |
132 { | 149 { |
133 assert(x < information_.GetWidth() && | 150 assert(x < information_.GetWidth() && |
134 y < information_.GetHeight() && | 151 y < information_.GetHeight() && |
135 channel < information_.GetChannelCount()); | 152 channel < information_.GetChannelCount()); |
153 | |
154 const uint8_t* pixel = (reinterpret_cast<const uint8_t*>(pixelData_) + | |
155 y * rowOffset_ + frame_ * frameOffset_); | |
136 | 156 |
137 const uint8_t* pixel = reinterpret_cast<const uint8_t*>(pixelData_) + | 157 if (information_.GetBitsStored() == 1) |
138 y * rowOffset_ + frame_ * frameOffset_; | 158 { |
139 | 159 // New in Orthanc 1.9.8, notably for DICOM SEG |
140 // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.3.1.3 | 160 assert(information_.GetBitsAllocated() == 1 && |
141 if (information_.IsPlanar()) | 161 information_.GetChannelCount() == 1 && |
142 { | 162 !information_.IsPlanar()); |
143 /** | 163 |
144 * Each color plane shall be sent contiguously. For RGB images, | 164 uint8_t b = pixel[x / 8]; |
145 * this means the order of the pixel values sent is R1, R2, R3, | 165 |
146 * ..., G1, G2, G3, ..., B1, B2, B3, etc. | 166 if (b & (1 << (x % 8))) |
147 **/ | 167 { |
148 assert(frameOffset_ % information_.GetChannelCount() == 0); | 168 return 255; |
149 pixel += channel * frameOffset_ / information_.GetChannelCount() + x * information_.GetBytesPerValue(); | 169 } |
170 else | |
171 { | |
172 return 0; | |
173 } | |
150 } | 174 } |
151 else | 175 else |
152 { | 176 { |
153 /** | 177 // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.3.1.3 |
154 * The sample values for the first pixel are followed by the | 178 if (information_.IsPlanar()) |
155 * sample values for the second pixel, etc. For RGB images, this | 179 { |
156 * means the order of the pixel values sent shall be R1, G1, B1, | 180 /** |
157 * R2, G2, B2, ..., etc. | 181 * Each color plane shall be sent contiguously. For RGB images, |
158 **/ | 182 * this means the order of the pixel values sent is R1, R2, R3, |
159 pixel += channel * information_.GetBytesPerValue() + x * information_.GetChannelCount() * information_.GetBytesPerValue(); | 183 * ..., G1, G2, G3, ..., B1, B2, B3, etc. |
160 } | 184 **/ |
161 | 185 assert(frameOffset_ % information_.GetChannelCount() == 0); |
162 uint32_t v; | 186 pixel += channel * frameOffset_ / information_.GetChannelCount() + x * information_.GetBytesPerValue(); |
163 v = pixel[0]; | 187 } |
164 if (information_.GetBytesPerValue() >= 2) | 188 else |
165 v = v + (static_cast<uint32_t>(pixel[1]) << 8); | 189 { |
166 if (information_.GetBytesPerValue() >= 3) | 190 /** |
167 v = v + (static_cast<uint32_t>(pixel[2]) << 16); | 191 * The sample values for the first pixel are followed by the |
168 if (information_.GetBytesPerValue() >= 4) | 192 * sample values for the second pixel, etc. For RGB images, this |
169 v = v + (static_cast<uint32_t>(pixel[3]) << 24); | 193 * means the order of the pixel values sent shall be R1, G1, B1, |
170 | 194 * R2, G2, B2, ..., etc. |
171 v = v >> information_.GetShift(); | 195 **/ |
172 | 196 pixel += channel * information_.GetBytesPerValue() + x * information_.GetChannelCount() * information_.GetBytesPerValue(); |
173 if (v & signMask_) | 197 } |
174 { | 198 |
175 // Signed value | 199 uint32_t v; |
176 // http://en.wikipedia.org/wiki/Two%27s_complement#Subtraction_from_2N | 200 v = pixel[0]; |
177 return -static_cast<int32_t>(mask_) + static_cast<int32_t>(v & mask_) - 1; | 201 if (information_.GetBytesPerValue() >= 2) |
178 } | 202 v = v + (static_cast<uint32_t>(pixel[1]) << 8); |
179 else | 203 if (information_.GetBytesPerValue() >= 3) |
180 { | 204 v = v + (static_cast<uint32_t>(pixel[2]) << 16); |
181 // Unsigned value | 205 if (information_.GetBytesPerValue() >= 4) |
182 return static_cast<int32_t>(v & mask_); | 206 v = v + (static_cast<uint32_t>(pixel[3]) << 24); |
207 | |
208 v = v >> information_.GetShift(); | |
209 | |
210 if (v & signMask_) | |
211 { | |
212 // Signed value | |
213 // http://en.wikipedia.org/wiki/Two%27s_complement#Subtraction_from_2N | |
214 return -static_cast<int32_t>(mask_) + static_cast<int32_t>(v & mask_) - 1; | |
215 } | |
216 else | |
217 { | |
218 // Unsigned value | |
219 return static_cast<int32_t>(v & mask_); | |
220 } | |
183 } | 221 } |
184 } | 222 } |
185 | 223 |
186 | 224 |
187 void DicomIntegerPixelAccessor::SetCurrentFrame(unsigned int frame) | 225 void DicomIntegerPixelAccessor::SetCurrentFrame(unsigned int frame) |