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 }