Mercurial > hg > orthanc-stone
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 |