comparison Samples/Sdl/Loader.cpp @ 793:f72b49954f62

DicomVolumeImageMPRSlicer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 May 2019 10:39:42 +0200
parents 4fe4b221a31f
children 04f518ebd132
comparison
equal deleted inserted replaced
792:4fe4b221a31f 793:f72b49954f62
341 } 341 }
342 }; 342 };
343 343
344 344
345 345
346 class DicomVolumeImageOrthogonalSlice : public IVolumeSlicer::IExtractedSlice 346 class DicomVolumeImageMPRSlicer : public IVolumeSlicer
347 { 347 {
348 public:
349 class Slice : public IExtractedSlice
350 {
351 private:
352 const DicomVolumeImage& volume_;
353 bool valid_;
354 VolumeProjection projection_;
355 unsigned int sliceIndex_;
356
357 void CheckValid() const
358 {
359 if (!valid_)
360 {
361 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
362 }
363 }
364
365 protected:
366 // Can be overloaded in subclasses
367 virtual uint64_t GetRevisionInternal(VolumeProjection projection,
368 unsigned int sliceIndex) const
369 {
370 return volume_.GetRevision();
371 }
372
373 public:
374 Slice(const DicomVolumeImage& volume,
375 const CoordinateSystem3D& cuttingPlane) :
376 volume_(volume)
377 {
378 valid_ = (volume_.HasDicomParameters() &&
379 volume_.GetGeometry().DetectSlice(projection_, sliceIndex_, cuttingPlane));
380 }
381
382 VolumeProjection GetProjection() const
383 {
384 CheckValid();
385 return projection_;
386 }
387
388 unsigned int GetSliceIndex() const
389 {
390 CheckValid();
391 return sliceIndex_;
392 }
393
394 virtual bool IsValid()
395 {
396 return valid_;
397 }
398
399 virtual uint64_t GetRevision()
400 {
401 CheckValid();
402 return GetRevisionInternal(projection_, sliceIndex_);
403 }
404
405 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator,
406 const CoordinateSystem3D& cuttingPlane)
407 {
408 CheckValid();
409
410 if (configurator == NULL)
411 {
412 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer,
413 "A style configurator is mandatory for textures");
414 }
415
416 std::auto_ptr<TextureBaseSceneLayer> texture;
417
418 {
419 const DicomInstanceParameters& parameters = volume_.GetDicomParameters();
420 ImageBuffer3D::SliceReader reader(volume_.GetPixelData(), projection_, sliceIndex_);
421 texture.reset(dynamic_cast<TextureBaseSceneLayer*>
422 (configurator->CreateTextureFromDicom(reader.GetAccessor(), parameters)));
423 }
424
425 const CoordinateSystem3D& system = volume_.GetGeometry().GetProjectionGeometry(projection_);
426
427 double x0, y0, x1, y1;
428 cuttingPlane.ProjectPoint(x0, y0, system.GetOrigin());
429 cuttingPlane.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX());
430 texture->SetOrigin(x0, y0);
431
432 double dx = x1 - x0;
433 double dy = y1 - y0;
434 if (!LinearAlgebra::IsCloseToZero(dx) ||
435 !LinearAlgebra::IsCloseToZero(dy))
436 {
437 texture->SetAngle(atan2(dy, dx));
438 }
439
440 Vector tmp = volume_.GetGeometry().GetVoxelDimensions(projection_);
441 texture->SetPixelSpacing(tmp[0], tmp[1]);
442
443 return texture.release();
444
445 #if 0
446 double w = texture->GetTexture().GetWidth() * tmp[0];
447 double h = texture->GetTexture().GetHeight() * tmp[1];
448 printf("%.1f %.1f %.1f => %.1f %.1f => %.1f %.1f\n",
449 system.GetOrigin() [0],
450 system.GetOrigin() [1],
451 system.GetOrigin() [2],
452 x0, y0, x0 + w, y0 + h);
453
454 std::auto_ptr<PolylineSceneLayer> toto(new PolylineSceneLayer);
455
456 PolylineSceneLayer::Chain c;
457 c.push_back(ScenePoint2D(x0, y0));
458 c.push_back(ScenePoint2D(x0 + w, y0));
459 c.push_back(ScenePoint2D(x0 + w, y0 + h));
460 c.push_back(ScenePoint2D(x0, y0 + h));
461
462 toto->AddChain(c, true);
463
464 return toto.release();
465 #endif
466 }
467 };
468
348 private: 469 private:
349 const DicomVolumeImage& volume_; 470 boost::shared_ptr<DicomVolumeImage> volume_;
350 bool valid_;
351 VolumeProjection projection_;
352 unsigned int sliceIndex_;
353
354 void CheckValid() const
355 {
356 if (!valid_)
357 {
358 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
359 }
360 }
361
362 protected:
363 // Can be overloaded in subclasses
364 virtual uint64_t GetRevisionInternal(VolumeProjection projection,
365 unsigned int sliceIndex) const
366 {
367 return volume_.GetRevision();
368 }
369 471
370 public: 472 public:
371 DicomVolumeImageOrthogonalSlice(const DicomVolumeImage& volume, 473 DicomVolumeImageMPRSlicer(const boost::shared_ptr<DicomVolumeImage>& volume) :
372 const CoordinateSystem3D& cuttingPlane) :
373 volume_(volume) 474 volume_(volume)
374 { 475 {
375 valid_ = (volume_.HasDicomParameters() && 476 }
376 volume_.GetGeometry().DetectSlice(projection_, sliceIndex_, cuttingPlane)); 477
377 } 478 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
378 479 {
379 VolumeProjection GetProjection() const 480 if (volume_->HasGeometry())
380 { 481 {
381 CheckValid(); 482 return new Slice(*volume_, cuttingPlane);
382 return projection_; 483 }
383 } 484 else
384 485 {
385 unsigned int GetSliceIndex() const 486 return new IVolumeSlicer::InvalidSlice;
386 { 487 }
387 CheckValid();
388 return sliceIndex_;
389 }
390
391 virtual bool IsValid()
392 {
393 return valid_;
394 }
395
396 virtual uint64_t GetRevision()
397 {
398 CheckValid();
399 return GetRevisionInternal(projection_, sliceIndex_);
400 }
401
402 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator,
403 const CoordinateSystem3D& cuttingPlane)
404 {
405 CheckValid();
406
407 if (configurator == NULL)
408 {
409 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer,
410 "A style configurator is mandatory for textures");
411 }
412
413 std::auto_ptr<TextureBaseSceneLayer> texture;
414
415 {
416 const DicomInstanceParameters& parameters = volume_.GetDicomParameters();
417 ImageBuffer3D::SliceReader reader(volume_.GetPixelData(), projection_, sliceIndex_);
418 texture.reset(dynamic_cast<TextureBaseSceneLayer*>
419 (configurator->CreateTextureFromDicom(reader.GetAccessor(), parameters)));
420 }
421
422 const CoordinateSystem3D& system = volume_.GetGeometry().GetProjectionGeometry(projection_);
423
424 double x0, y0, x1, y1;
425 cuttingPlane.ProjectPoint(x0, y0, system.GetOrigin());
426 cuttingPlane.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX());
427 texture->SetOrigin(x0, y0);
428
429 double dx = x1 - x0;
430 double dy = y1 - y0;
431 if (!LinearAlgebra::IsCloseToZero(dx) ||
432 !LinearAlgebra::IsCloseToZero(dy))
433 {
434 texture->SetAngle(atan2(dy, dx));
435 }
436
437 Vector tmp = volume_.GetGeometry().GetVoxelDimensions(projection_);
438 texture->SetPixelSpacing(tmp[0], tmp[1]);
439
440 return texture.release();
441
442 #if 0
443 double w = texture->GetTexture().GetWidth() * tmp[0];
444 double h = texture->GetTexture().GetHeight() * tmp[1];
445 printf("%.1f %.1f %.1f => %.1f %.1f => %.1f %.1f\n",
446 system.GetOrigin() [0],
447 system.GetOrigin() [1],
448 system.GetOrigin() [2],
449 x0, y0, x0 + w, y0 + h);
450
451 std::auto_ptr<PolylineSceneLayer> toto(new PolylineSceneLayer);
452
453 PolylineSceneLayer::Chain c;
454 c.push_back(ScenePoint2D(x0, y0));
455 c.push_back(ScenePoint2D(x0 + w, y0));
456 c.push_back(ScenePoint2D(x0 + w, y0 + h));
457 c.push_back(ScenePoint2D(x0, y0 + h));
458
459 toto->AddChain(c, true);
460
461 return toto.release();
462 #endif
463 } 488 }
464 }; 489 };
465 490
466 491
467 492
662 slicesRevision_[index] ++; 687 slicesRevision_[index] ++;
663 } 688 }
664 }; 689 };
665 690
666 691
667 class Slice : public DicomVolumeImageOrthogonalSlice 692 class ExtractedSlice : public DicomVolumeImageMPRSlicer::Slice
668 { 693 {
669 private: 694 private:
670 const OrthancSeriesVolumeProgressiveLoader& that_; 695 const OrthancSeriesVolumeProgressiveLoader& that_;
671 696
672 protected: 697 protected:
684 return that_.volume_->GetRevision(); 709 return that_.volume_->GetRevision();
685 } 710 }
686 } 711 }
687 712
688 public: 713 public:
689 Slice(const OrthancSeriesVolumeProgressiveLoader& that, 714 ExtractedSlice(const OrthancSeriesVolumeProgressiveLoader& that,
690 const CoordinateSystem3D& plane) : 715 const CoordinateSystem3D& plane) :
691 DicomVolumeImageOrthogonalSlice(*that.volume_, plane), 716 DicomVolumeImageMPRSlicer::Slice(*that.volume_, plane),
692 that_(that) 717 that_(that)
693 { 718 {
719 if (that_.strategy_.get() != NULL &&
720 IsValid() &&
721 GetProjection() == VolumeProjection_Axial)
722 {
723 that_.strategy_->SetCurrent(GetSliceIndex());
724 }
694 } 725 }
695 }; 726 };
696 727
697 728
698 729
931 962
932 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) 963 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
933 { 964 {
934 if (volume_->HasGeometry()) 965 if (volume_->HasGeometry())
935 { 966 {
936 std::auto_ptr<Slice> slice(new Slice(*this, cuttingPlane)); 967 return new ExtractedSlice(*this, cuttingPlane);
937
938 if (strategy_.get() != NULL &&
939 slice->IsValid() &&
940 slice->GetProjection() == VolumeProjection_Axial)
941 {
942 strategy_->SetCurrent(slice->GetSliceIndex());
943 }
944
945 return slice.release();
946 } 968 }
947 else 969 else
948 { 970 {
949 return new IVolumeSlicer::InvalidSlice; 971 return new IVolumeSlicer::InvalidSlice;
950 } 972 }
953 975
954 976
955 977
956 class OrthancMultiframeVolumeLoader : 978 class OrthancMultiframeVolumeLoader :
957 public IObserver, 979 public IObserver,
958 public IObservable, 980 public IObservable
959 public IVolumeSlicer
960 { 981 {
961 private: 982 private:
962 class State : public Orthanc::IDynamicObject 983 class State : public Orthanc::IDynamicObject
963 { 984 {
964 private: 985 private:
1327 command->SetPayload(new LoadTransferSyntax(*this)); 1348 command->SetPayload(new LoadTransferSyntax(*this));
1328 oracle_.Schedule(*this, command.release()); 1349 oracle_.Schedule(*this, command.release());
1329 } 1350 }
1330 } 1351 }
1331 } 1352 }
1332
1333
1334 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
1335 {
1336 if (volume_->HasGeometry())
1337 {
1338 return new DicomVolumeImageOrthogonalSlice(*volume_, cuttingPlane);
1339 }
1340 else
1341 {
1342 return new IVolumeSlicer::InvalidSlice;
1343 }
1344 }
1345 }; 1353 };
1346 1354
1347 1355
1348 1356
1349 class VolumeImageReslicer : public IVolumeSlicer 1357 class VolumeImageReslicer : public IVolumeSlicer
1960 1968
1961 1969
1962 { 1970 {
1963 std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator); 1971 std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator);
1964 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT); 1972 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
1965 toto->SetVolume2(1, doseLoader, config.release()); 1973
1966 } 1974 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> tmp(new OrthancStone::DicomVolumeImageMPRSlicer(dose));
1967 1975 toto->SetVolume2(1, tmp, config.release());
1968 //oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100)); 1976 }
1977
1978 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100));
1969 1979
1970 if (0) 1980 if (0)
1971 { 1981 {
1972 Json::Value v = Json::objectValue; 1982 Json::Value v = Json::objectValue;
1973 v["Level"] = "Series"; 1983 v["Level"] = "Series";
2042 } 2052 }
2043 } 2053 }
2044 2054
2045 2055
2046 // 2017-11-17-Anonymized 2056 // 2017-11-17-Anonymized
2047 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT 2057 ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT
2048 //doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE 2058 doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE
2049 rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT 2059 rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT
2050 2060
2051 // 2015-01-28-Multiframe 2061 // 2015-01-28-Multiframe
2052 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT 2062 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT
2053 2063