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)