Mercurial > hg > orthanc-stone
comparison Framework/Toolbox/DicomInstanceParameters.cpp @ 1141:7681f3943748
Changed handling of DoseGridScaling: before this commit, rescaleSlope was set to
the DoseGridScaling value if rescale* tags weren't present AND in the case of a
dose. This caused issues in dose files where all three tags (DoseGridScaling,
RescaleSlope and RescaleIntercept) were present, which previously led to the
DoseGridScaling tag to be ignored. Now, the rescale* tags are *ignored* in dose
files and DoseGridScaling is always taken into account.
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Fri, 08 Nov 2019 14:25:35 +0100 |
parents | 5a18e6a395bc |
children | acb399643945 c93a6218f0cd |
comparison
equal
deleted
inserted
replaced
1123:45df56448b2a | 1141:7681f3943748 |
---|---|
113 | 113 |
114 static const Orthanc::DicomTag DICOM_TAG_DOSE_UNITS(0x3004, 0x0002); | 114 static const Orthanc::DicomTag DICOM_TAG_DOSE_UNITS(0x3004, 0x0002); |
115 | 115 |
116 if (!dicom.LookupStringValue(doseUnits_, DICOM_TAG_DOSE_UNITS, false)) | 116 if (!dicom.LookupStringValue(doseUnits_, DICOM_TAG_DOSE_UNITS, false)) |
117 { | 117 { |
118 LOG(WARNING) << "Tag DoseUnits (0x3004, 0x0002) is missing in " << sopInstanceUid_; | 118 LOG(ERROR) << "Tag DoseUnits (0x3004, 0x0002) is missing in " << sopInstanceUid_; |
119 doseUnits_ = ""; | 119 doseUnits_ = ""; |
120 } | 120 } |
121 | |
122 } | 121 } |
123 | 122 |
124 isColor_ = (imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome1 && | 123 isColor_ = (imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome1 && |
125 imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome2); | 124 imageInformation_.GetPhotometricInterpretation() != Orthanc::PhotometricInterpretation_Monochrome2); |
126 | 125 |
127 double doseGridScaling; | |
128 | |
129 if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) && | 126 if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) && |
130 dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE)) | 127 dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE)) |
131 { | 128 { |
132 hasRescale_ = true; | 129 if (sopClassUid_ == SopClassUid_RTDose) |
133 } | 130 { |
134 else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING)) | 131 LOG(INFO) << "DOSE HAS Rescale*: rescaleIntercept_ = " << rescaleIntercept_ << " rescaleSlope_ = " << rescaleSlope_; |
135 { | 132 // WE SHOULD NOT TAKE THE RESCALE VALUE INTO ACCOUNT IN THE CASE OF DOSES |
136 hasRescale_ = true; | 133 hasRescale_ = false; |
137 rescaleIntercept_ = 0; | 134 } |
138 rescaleSlope_ = doseGridScaling; | 135 else |
136 { | |
137 hasRescale_ = true; | |
138 } | |
139 | |
139 } | 140 } |
140 else | 141 else |
141 { | 142 { |
142 hasRescale_ = false; | 143 hasRescale_ = false; |
144 } | |
145 | |
146 if (dicom.ParseDouble(doseGridScaling_, Orthanc::DICOM_TAG_DOSE_GRID_SCALING)) | |
147 { | |
148 if (sopClassUid_ == SopClassUid_RTDose) | |
149 { | |
150 LOG(INFO) << "DOSE HAS DoseGridScaling: doseGridScaling_ = " << doseGridScaling_; | |
151 } | |
152 } | |
153 else | |
154 { | |
155 doseGridScaling_ = 1.0; | |
156 if (sopClassUid_ == SopClassUid_RTDose) | |
157 { | |
158 LOG(ERROR) << "Tag DoseGridScaling (0x3004, 0x000e) is missing in " << sopInstanceUid_ << " doseGridScaling_ will be set to 1.0"; | |
159 } | |
143 } | 160 } |
144 | 161 |
145 Vector c, w; | 162 Vector c, w; |
146 if (LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) && | 163 if (LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) && |
147 LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) && | 164 LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) && |
153 defaultWindowingWidth_ = static_cast<float>(w[0]); | 170 defaultWindowingWidth_ = static_cast<float>(w[0]); |
154 } | 171 } |
155 else | 172 else |
156 { | 173 { |
157 hasDefaultWindowing_ = false; | 174 hasDefaultWindowing_ = false; |
175 defaultWindowingCenter_ = 0; | |
176 defaultWindowingWidth_ = 0; | |
158 } | 177 } |
159 | 178 |
160 if (sopClassUid_ == SopClassUid_RTDose) | 179 if (sopClassUid_ == SopClassUid_RTDose) |
161 { | 180 { |
162 switch (imageInformation_.GetBitsStored()) | 181 switch (imageInformation_.GetBitsStored()) |
243 return (CoordinateSystem3D::ComputeDistance(distance, tmp, plane) && | 262 return (CoordinateSystem3D::ComputeDistance(distance, tmp, plane) && |
244 distance <= thickness_ / 2.0); | 263 distance <= thickness_ / 2.0); |
245 } | 264 } |
246 | 265 |
247 | 266 |
248 void DicomInstanceParameters::Data::ApplyRescale(Orthanc::ImageAccessor& image, | 267 void DicomInstanceParameters::Data::ApplyRescaleAndDoseScaling(Orthanc::ImageAccessor& image, |
249 bool useDouble) const | 268 bool useDouble) const |
250 { | 269 { |
251 if (image.GetFormat() != Orthanc::PixelFormat_Float32) | 270 if (image.GetFormat() != Orthanc::PixelFormat_Float32) |
252 { | 271 { |
253 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); | 272 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); |
254 } | 273 } |
255 | 274 |
275 double factor = doseGridScaling_; | |
276 double offset = 0.0; | |
277 | |
256 if (hasRescale_) | 278 if (hasRescale_) |
279 { | |
280 factor *= rescaleSlope_; | |
281 offset = rescaleIntercept_; | |
282 } | |
283 | |
284 if ( (factor != 1.0) || (offset != 0.0) ) | |
257 { | 285 { |
258 const unsigned int width = image.GetWidth(); | 286 const unsigned int width = image.GetWidth(); |
259 const unsigned int height = image.GetHeight(); | 287 const unsigned int height = image.GetHeight(); |
260 | 288 |
261 for (unsigned int y = 0; y < height; y++) | 289 for (unsigned int y = 0; y < height; y++) |
266 { | 294 { |
267 // Slower, accurate implementation using double | 295 // Slower, accurate implementation using double |
268 for (unsigned int x = 0; x < width; x++, p++) | 296 for (unsigned int x = 0; x < width; x++, p++) |
269 { | 297 { |
270 double value = static_cast<double>(*p); | 298 double value = static_cast<double>(*p); |
271 *p = static_cast<float>(value * rescaleSlope_ + rescaleIntercept_); | 299 *p = static_cast<float>(value * factor + offset); |
272 } | 300 } |
273 } | 301 } |
274 else | 302 else |
275 { | 303 { |
276 // Fast, approximate implementation using float | 304 // Fast, approximate implementation using float |
277 for (unsigned int x = 0; x < width; x++, p++) | 305 for (unsigned int x = 0; x < width; x++, p++) |
278 { | 306 { |
279 *p = (*p) * static_cast<float>(rescaleSlope_) + static_cast<float>(rescaleIntercept_); | 307 *p = (*p) * static_cast<float>(factor) + static_cast<float>(offset); |
280 } | 308 } |
281 } | 309 } |
282 } | 310 } |
283 } | 311 } |
284 } | 312 } |
346 pixelData.GetHeight(), | 374 pixelData.GetHeight(), |
347 false)); | 375 false)); |
348 Orthanc::ImageProcessing::Convert(*converted, pixelData); | 376 Orthanc::ImageProcessing::Convert(*converted, pixelData); |
349 | 377 |
350 // Correct rescale slope/intercept if need be | 378 // Correct rescale slope/intercept if need be |
351 //data_.ApplyRescale(*converted, (pixelData.GetFormat() == Orthanc::PixelFormat_Grayscale32)); | 379 //data_.ApplyRescaleAndDoseScaling(*converted, (pixelData.GetFormat() == Orthanc::PixelFormat_Grayscale32)); |
352 data_.ApplyRescale(*converted, false); | 380 data_.ApplyRescaleAndDoseScaling(*converted, false); |
353 | 381 |
354 return converted.release(); | 382 return converted.release(); |
355 } | 383 } |
356 | 384 |
357 | 385 |