Mercurial > hg > orthanc-stone
comparison OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp @ 1636:d1e0b08b809d
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 10 Nov 2020 16:20:22 +0100 |
parents | 1a714e21ea7c |
children | d569effcd433 |
comparison
equal
deleted
inserted
replaced
1635:1a714e21ea7c | 1636:d1e0b08b809d |
---|---|
34 #include <Toolbox.h> | 34 #include <Toolbox.h> |
35 | 35 |
36 | 36 |
37 namespace OrthancStone | 37 namespace OrthancStone |
38 { | 38 { |
39 void DicomInstanceParameters::Data::ExtractFrameOffsets(const Orthanc::DicomMap& dicom) | 39 static void ExtractFrameOffsets(Vector& target, |
40 const Orthanc::DicomMap& dicom, | |
41 unsigned int numberOfFrames) | |
40 { | 42 { |
41 // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html | 43 // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html |
42 | 44 |
43 std::string increment; | 45 std::string increment; |
44 | 46 |
48 | 50 |
49 // This is the "Grid Frame Offset Vector" tag (DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) | 51 // This is the "Grid Frame Offset Vector" tag (DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) |
50 if (increment != "3004,000C") | 52 if (increment != "3004,000C") |
51 { | 53 { |
52 LOG(WARNING) << "Bad value for the FrameIncrementPointer tags in a multiframe image"; | 54 LOG(WARNING) << "Bad value for the FrameIncrementPointer tags in a multiframe image"; |
53 frameOffsets_.resize(0); | 55 target.resize(0); |
54 return; | 56 return; |
55 } | 57 } |
56 } | 58 } |
57 | 59 |
58 if (!LinearAlgebra::ParseVector(frameOffsets_, dicom, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) || | 60 if (!LinearAlgebra::ParseVector(target, dicom, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR) || |
59 frameOffsets_.size() != numberOfFrames_) | 61 target.size() != numberOfFrames) |
60 { | 62 { |
61 LOG(INFO) << "The frame offset information is missing in a multiframe image"; | 63 LOG(INFO) << "The frame offset information is missing in a multiframe image"; |
62 | 64 |
63 // DO NOT use ".clear()" here, as the "Vector" class doesn't behave like std::vector! | 65 // DO NOT use ".clear()" here, as the "Vector" class doesn't behave like std::vector! |
64 frameOffsets_.resize(0); | 66 target.resize(0); |
65 } | 67 } |
66 } | 68 } |
67 | 69 |
68 | 70 |
69 DicomInstanceParameters::Data::Data(const Orthanc::DicomMap& dicom) : | 71 DicomInstanceParameters::Data::Data(const Orthanc::DicomMap& dicom) : |
121 { | 123 { |
122 geometry_ = CoordinateSystem3D(position, orientation); | 124 geometry_ = CoordinateSystem3D(position, orientation); |
123 } | 125 } |
124 | 126 |
125 // Must be AFTER setting "numberOfFrames_" | 127 // Must be AFTER setting "numberOfFrames_" |
126 ExtractFrameOffsets(dicom); | 128 ExtractFrameOffsets(frameOffsets_, dicom, numberOfFrames_); |
127 | 129 |
128 if (sopClassUid_ == SopClassUid_RTDose) | 130 if (sopClassUid_ == SopClassUid_RTDose) |
129 { | 131 { |
130 static const Orthanc::DicomTag DICOM_TAG_DOSE_UNITS(0x3004, 0x0002); | 132 static const Orthanc::DicomTag DICOM_TAG_DOSE_UNITS(0x3004, 0x0002); |
131 | 133 |
225 dicom.ParseUnsignedInteger32(indexInSeries_, Orthanc::DICOM_TAG_INSTANCE_NUMBER) || | 227 dicom.ParseUnsignedInteger32(indexInSeries_, Orthanc::DICOM_TAG_INSTANCE_NUMBER) || |
226 dicom.ParseUnsignedInteger32(indexInSeries_, Orthanc::DICOM_TAG_IMAGE_INDEX)); | 228 dicom.ParseUnsignedInteger32(indexInSeries_, Orthanc::DICOM_TAG_IMAGE_INDEX)); |
227 } | 229 } |
228 | 230 |
229 | 231 |
230 CoordinateSystem3D DicomInstanceParameters::Data::GetFrameGeometry(unsigned int frame) const | 232 CoordinateSystem3D DicomInstanceParameters::GetFrameGeometry(unsigned int frame) const |
231 { | 233 { |
232 if (frame >= numberOfFrames_) | 234 if (frame >= data_.numberOfFrames_) |
233 { | 235 { |
234 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 236 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
235 } | 237 } |
236 else if (frameOffsets_.empty()) | 238 else if (data_.frameOffsets_.empty()) |
237 { | 239 { |
238 return geometry_; | 240 return data_.geometry_; |
239 } | 241 } |
240 else | 242 else |
241 { | 243 { |
242 assert(frameOffsets_.size() == numberOfFrames_); | 244 assert(data_.frameOffsets_.size() == data_.numberOfFrames_); |
243 | 245 |
244 return CoordinateSystem3D( | 246 return CoordinateSystem3D( |
245 geometry_.GetOrigin() + frameOffsets_[frame] * geometry_.GetNormal(), | 247 data_.geometry_.GetOrigin() + data_.frameOffsets_[frame] * data_.geometry_.GetNormal(), |
246 geometry_.GetAxisX(), | 248 data_.geometry_.GetAxisX(), |
247 geometry_.GetAxisY()); | 249 data_.geometry_.GetAxisY()); |
248 } | 250 } |
249 } | 251 } |
250 | 252 |
251 | 253 |
252 bool DicomInstanceParameters::Data::IsPlaneWithinSlice(unsigned int frame, | 254 bool DicomInstanceParameters::IsPlaneWithinSlice(unsigned int frame, |
253 const CoordinateSystem3D& plane) const | 255 const CoordinateSystem3D& plane) const |
254 { | 256 { |
255 if (frame >= numberOfFrames_) | 257 if (frame >= data_.numberOfFrames_) |
256 { | 258 { |
257 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 259 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
258 } | 260 } |
259 | 261 |
260 CoordinateSystem3D tmp = geometry_; | 262 CoordinateSystem3D tmp = data_.geometry_; |
261 | 263 |
262 if (frame != 0) | 264 if (frame != 0) |
263 { | 265 { |
264 tmp = GetFrameGeometry(frame); | 266 tmp = GetFrameGeometry(frame); |
265 } | 267 } |
266 | 268 |
267 double distance; | 269 double distance; |
268 | 270 |
269 return (CoordinateSystem3D::ComputeDistance(distance, tmp, plane) && | 271 return (CoordinateSystem3D::ComputeDistance(distance, tmp, plane) && |
270 distance <= sliceThickness_ / 2.0); | 272 distance <= data_.sliceThickness_ / 2.0); |
271 } | 273 } |
272 | 274 |
273 void DicomInstanceParameters::Data::ApplyRescaleAndDoseScaling(Orthanc::ImageAccessor& image, | 275 void DicomInstanceParameters::ApplyRescaleAndDoseScaling(Orthanc::ImageAccessor& image, |
274 bool useDouble) const | 276 bool useDouble) const |
275 { | 277 { |
276 if (image.GetFormat() != Orthanc::PixelFormat_Float32) | 278 if (image.GetFormat() != Orthanc::PixelFormat_Float32) |
277 { | 279 { |
278 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); | 280 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); |
279 } | 281 } |
280 | 282 |
281 double factor = doseGridScaling_; | 283 double factor = data_.doseGridScaling_; |
282 double offset = 0.0; | 284 double offset = 0.0; |
283 | 285 |
284 if (hasRescale_) | 286 if (data_.hasRescale_) |
285 { | 287 { |
286 factor *= rescaleSlope_; | 288 factor *= data_.rescaleSlope_; |
287 offset = rescaleIntercept_; | 289 offset = data_.rescaleIntercept_; |
288 } | 290 } |
289 | 291 |
290 if (!LinearAlgebra::IsNear(factor, 1) || | 292 if (!LinearAlgebra::IsNear(factor, 1) || |
291 !LinearAlgebra::IsNear(offset, 0)) | 293 !LinearAlgebra::IsNear(offset, 0)) |
292 { | 294 { |
382 false)); | 384 false)); |
383 Orthanc::ImageProcessing::Convert(*converted, pixelData); | 385 Orthanc::ImageProcessing::Convert(*converted, pixelData); |
384 | 386 |
385 | 387 |
386 // Correct rescale slope/intercept if need be | 388 // Correct rescale slope/intercept if need be |
387 //data_.ApplyRescaleAndDoseScaling(*converted, (pixelData.GetFormat() == Orthanc::PixelFormat_Grayscale32)); | 389 //ApplyRescaleAndDoseScaling(*converted, (pixelData.GetFormat() == Orthanc::PixelFormat_Grayscale32)); |
388 data_.ApplyRescaleAndDoseScaling(*converted, false); | 390 ApplyRescaleAndDoseScaling(*converted, false); |
389 | 391 |
390 return converted.release(); | 392 return converted.release(); |
391 } | 393 } |
392 | 394 |
393 | 395 |
492 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 494 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
493 } | 495 } |
494 } | 496 } |
495 | 497 |
496 | 498 |
497 double DicomInstanceParameters::Data::ApplyRescale(double value) const | 499 double DicomInstanceParameters::ApplyRescale(double value) const |
498 { | 500 { |
499 double factor = doseGridScaling_; | 501 double factor = data_.doseGridScaling_; |
500 double offset = 0.0; | 502 double offset = 0.0; |
501 | 503 |
502 if (hasRescale_) | 504 if (data_.hasRescale_) |
503 { | 505 { |
504 factor *= rescaleSlope_; | 506 factor *= data_.rescaleSlope_; |
505 offset = rescaleIntercept_; | 507 offset = data_.rescaleIntercept_; |
506 } | 508 } |
507 | 509 |
508 return (value * factor + offset); | 510 return (value * factor + offset); |
509 } | 511 } |
510 | 512 |
511 | 513 |
512 bool DicomInstanceParameters::Data::ComputeRegularSpacing(double& spacing) const | 514 bool DicomInstanceParameters::ComputeRegularSpacing(double& spacing) const |
513 { | 515 { |
514 if (frameOffsets_.size() == 0) // Not a RT-DOSE | 516 if (data_.frameOffsets_.size() == 0) // Not a RT-DOSE |
515 { | 517 { |
516 return false; | 518 return false; |
517 } | 519 } |
518 else if (frameOffsets_.size() == 1) | 520 else if (data_.frameOffsets_.size() == 1) |
519 { | 521 { |
520 spacing = 1; // Edge case: RT-DOSE with one single frame | 522 spacing = 1; // Edge case: RT-DOSE with one single frame |
521 return true; | 523 return true; |
522 } | 524 } |
523 else | 525 else |
524 { | 526 { |
525 spacing = std::abs(frameOffsets_[1] - frameOffsets_[0]); | 527 assert(data_.frameOffsets_.size() == GetNumberOfFrames()); |
526 | 528 |
527 for (size_t i = 1; i + 1 < frameOffsets_.size(); i++) | 529 spacing = std::abs(data_.frameOffsets_[1] - data_.frameOffsets_[0]); |
528 { | 530 |
529 double s = frameOffsets_[i + 1] - frameOffsets_[i]; | 531 for (size_t i = 1; i + 1 < data_.frameOffsets_.size(); i++) |
532 { | |
533 double s = data_.frameOffsets_[i + 1] - data_.frameOffsets_[i]; | |
530 if (!LinearAlgebra::IsNear(spacing, s, 0.001)) | 534 if (!LinearAlgebra::IsNear(spacing, s, 0.001)) |
531 { | 535 { |
532 return false; | 536 return false; |
533 } | 537 } |
534 } | 538 } |