Mercurial > hg > orthanc-stone
comparison UnitTestsSources/TestStructureSet.cpp @ 1445:04d0c25819c3 loader-injection-feature
Added integration test for optimized CT / RTSTRUCT loading
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Tue, 26 May 2020 17:12:34 +0200 |
parents | 4e7751a4b603 |
children | ab00f36718ed |
comparison
equal
deleted
inserted
replaced
1444:687457d4018f | 1445:04d0c25819c3 |
---|---|
32 #include "Framework/Toolbox/DicomStructureSet2.h" | 32 #include "Framework/Toolbox/DicomStructureSet2.h" |
33 #include "Framework/Toolbox/DisjointDataSet.h" | 33 #include "Framework/Toolbox/DisjointDataSet.h" |
34 | 34 |
35 #include "Framework/Loaders/GenericLoadersContext.h" | 35 #include "Framework/Loaders/GenericLoadersContext.h" |
36 #include "Framework/Loaders/DicomStructureSetLoader.h" | 36 #include "Framework/Loaders/DicomStructureSetLoader.h" |
37 #include "Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h" | |
37 | 38 |
38 #include "boost/date_time/posix_time/posix_time.hpp" | 39 #include "boost/date_time/posix_time/posix_time.hpp" |
39 | 40 |
40 #include <Core/SystemToolbox.h> | 41 #include <Core/SystemToolbox.h> |
41 | 42 |
5451 }; | 5452 }; |
5452 #endif | 5453 #endif |
5453 | 5454 |
5454 } | 5455 } |
5455 | 5456 |
5456 | |
5457 TEST(StructureSet, DISABLED_StructureSetLoader_injection_feature_2020_05_10) | 5457 TEST(StructureSet, DISABLED_StructureSetLoader_injection_feature_2020_05_10) |
5458 { | 5458 { |
5459 namespace pt = boost::posix_time; | 5459 namespace pt = boost::posix_time; |
5460 | 5460 |
5461 std::unique_ptr<OrthancStone::ILoadersContext> loadersContext(new OrthancStone::GenericLoadersContext(1,4,1)); | 5461 std::unique_ptr<OrthancStone::ILoadersContext> loadersContext(new OrthancStone::GenericLoadersContext(1,4,1)); |
5488 } | 5488 } |
5489 } | 5489 } |
5490 } | 5490 } |
5491 } | 5491 } |
5492 | 5492 |
5493 | 5493 class SliceProcessor : |
5494 public OrthancStone::OrthancSeriesVolumeProgressiveLoader::ISlicePostProcessor, | |
5495 public OrthancStone::DicomStructureSetLoader::IInstanceLookupHandler | |
5496 { | |
5497 public: | |
5498 SliceProcessor(OrthancStone::DicomStructureSetLoader& structLoader) : structLoader_(structLoader) | |
5499 { | |
5500 } | |
5501 | |
5502 virtual void ProcessCTDicomSlice(const Orthanc::DicomMap& instance) ORTHANC_OVERRIDE | |
5503 { | |
5504 std::string sopInstanceUid; | |
5505 if (!instance.LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false)) | |
5506 { | |
5507 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Missing SOPInstanceUID in a DICOM instance"); | |
5508 } | |
5509 slicesDicom_[sopInstanceUid] = boost::shared_ptr<DicomMap>(instance.Clone()); | |
5510 } | |
5511 | |
5512 virtual void RetrieveReferencedSlices(const std::set<std::string>& nonEmptyInstances) ORTHANC_OVERRIDE | |
5513 { | |
5514 for (std::set<std::string>::const_iterator it = nonEmptyInstances.begin(); | |
5515 it != nonEmptyInstances.end(); | |
5516 ++it) | |
5517 { | |
5518 const std::string nonEmptyInstance = *it; | |
5519 if (slicesDicom_.find(nonEmptyInstance) == slicesDicom_.end()) | |
5520 { | |
5521 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Referenced SOPInstanceUID not found in CT"); | |
5522 } | |
5523 boost::shared_ptr<Orthanc::DicomMap> instance = slicesDicom_[nonEmptyInstance]; | |
5524 structLoader_.AddReferencedSlice(*instance); | |
5525 } | |
5526 } | |
5527 | |
5528 OrthancStone::DicomStructureSetLoader& structLoader_; | |
5529 std::map<std::string, boost::shared_ptr<Orthanc::DicomMap> > slicesDicom_; | |
5530 }; | |
5531 | |
5532 void LoadCtSeriesBlocking(boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> ctLoader, std::string seriesId) | |
5533 { | |
5534 namespace pt = boost::posix_time; | |
5535 | |
5536 // Load the CT | |
5537 ctLoader->LoadSeries(seriesId); | |
5538 | |
5539 // Wait for CT to be loaded | |
5540 pt::ptime initialTime = pt::second_clock::local_time(); | |
5541 { | |
5542 bool bContinue(true); | |
5543 while (bContinue) | |
5544 { | |
5545 bContinue = !ctLoader->IsVolumeImageReadyInHighQuality(); | |
5546 boost::this_thread::sleep_for(boost::chrono::milliseconds(1000)); | |
5547 | |
5548 { | |
5549 pt::ptime nowTime = pt::second_clock::local_time(); | |
5550 pt::time_duration diff = nowTime - initialTime; | |
5551 double seconds = static_cast<double>(diff.total_milliseconds()) * 0.001; | |
5552 std::cout << seconds << " seconds elapsed...\n"; | |
5553 if (seconds > 30) | |
5554 { | |
5555 const char* msg = "More than 30 seconds elapsed when waiting for CT... Aborting test :(\n"; | |
5556 GTEST_FATAL_FAILURE_(msg); | |
5557 bContinue = false; | |
5558 } | |
5559 } | |
5560 } | |
5561 } | |
5562 } | |
5563 | |
5564 | |
5565 void LoadRtStructBlocking(boost::shared_ptr<OrthancStone::DicomStructureSetLoader> structLoader, std::string instanceId) | |
5566 { | |
5567 namespace pt = boost::posix_time; | |
5568 | |
5569 // Load RTSTRUCT | |
5570 structLoader->LoadInstanceFullVisibility(instanceId); | |
5571 | |
5572 pt::ptime initialTime = pt::second_clock::local_time(); | |
5573 | |
5574 // Wait for the loading process to complete | |
5575 { | |
5576 bool bContinue(true); | |
5577 while (bContinue) | |
5578 { | |
5579 bContinue = !structLoader->AreStructuresReady(); | |
5580 boost::this_thread::sleep_for(boost::chrono::milliseconds(1000)); | |
5581 | |
5582 { | |
5583 pt::ptime nowTime = pt::second_clock::local_time(); | |
5584 pt::time_duration diff = nowTime - initialTime; | |
5585 double seconds = static_cast<double>(diff.total_milliseconds()) * 0.001; | |
5586 std::cout << seconds << " seconds elapsed...\n"; | |
5587 if (seconds > 30) | |
5588 { | |
5589 const char* msg = "More than 30 seconds elapsed when waiting for RTSTRUCT... Aborting test :(\n"; | |
5590 GTEST_FATAL_FAILURE_(msg); | |
5591 bContinue = false; | |
5592 } | |
5593 } | |
5594 } | |
5595 } | |
5596 } | |
5597 | |
5598 TEST(StructureSet, DISABLED_Integration_Compound_CT_Struct_Loading) | |
5599 { | |
5600 const double TOLERANCE = 0.0000001; | |
5601 | |
5602 // create loaders context | |
5603 std::unique_ptr<OrthancStone::ILoadersContext> loadersContext(new OrthancStone::GenericLoadersContext(1,4,1)); | |
5604 Initialize("http://localhost:8042/", *loadersContext); | |
5605 | |
5606 const char* ctSeriesId = "a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"; | |
5607 const char* rtStructInstanceId = "54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"; | |
5608 | |
5609 // we'll compare normal loading and optimized loading with SliceProcessor to store the dicom | |
5610 | |
5611 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> normalStructLoader; | |
5612 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> optimizedStructLoader; | |
5613 | |
5614 { | |
5615 // Create the CT volume | |
5616 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume = boost::make_shared<OrthancStone::DicomVolumeImage>(); | |
5617 | |
5618 // Create CT loader | |
5619 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> ctLoader = | |
5620 OrthancStone::OrthancSeriesVolumeProgressiveLoader::Create(*loadersContext, volume); | |
5621 | |
5622 // Create struct loader | |
5623 normalStructLoader = OrthancStone::DicomStructureSetLoader::Create(*loadersContext); | |
5624 | |
5625 // Load the CT | |
5626 LoadCtSeriesBlocking(ctLoader, ctSeriesId); | |
5627 | |
5628 const OrthancStone::VolumeImageGeometry& imageGeometry = ctLoader->GetImageGeometry(); | |
5629 unsigned int width = imageGeometry.GetWidth(); | |
5630 EXPECT_EQ(512u, width); | |
5631 unsigned int height = imageGeometry.GetHeight(); | |
5632 EXPECT_EQ(512u, height); | |
5633 unsigned int depth = imageGeometry.GetDepth(); | |
5634 EXPECT_EQ(109u, depth); | |
5635 | |
5636 // Load the RTStruct | |
5637 LoadRtStructBlocking(normalStructLoader, rtStructInstanceId); | |
5638 } | |
5639 | |
5640 { | |
5641 // Create the CT volume | |
5642 boost::shared_ptr<OrthancStone::DicomVolumeImage> volume = boost::make_shared<OrthancStone::DicomVolumeImage>(); | |
5643 | |
5644 // Create CT loader | |
5645 boost::shared_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> ctLoader = | |
5646 OrthancStone::OrthancSeriesVolumeProgressiveLoader::Create(*loadersContext, volume); | |
5647 | |
5648 // Create struct loader | |
5649 optimizedStructLoader = OrthancStone::DicomStructureSetLoader::Create(*loadersContext); | |
5650 | |
5651 // create the slice processor / instance lookup | |
5652 boost::shared_ptr<SliceProcessor> sliceProcessor = boost::make_shared<SliceProcessor>(*optimizedStructLoader); | |
5653 | |
5654 // Inject it into CT loader | |
5655 ctLoader->SetDicomSlicePostProcessor(sliceProcessor); | |
5656 | |
5657 // Inject it into RTSTRUCT loader | |
5658 optimizedStructLoader->SetInstanceLookupHandler(sliceProcessor); | |
5659 | |
5660 // Load the CT | |
5661 LoadCtSeriesBlocking(ctLoader, ctSeriesId); | |
5662 | |
5663 // now, the slices are collected. let's do some checks | |
5664 EXPECT_EQ(109u, sliceProcessor->slicesDicom_.size()); | |
5665 | |
5666 // Load the RTStruct | |
5667 LoadRtStructBlocking(optimizedStructLoader, rtStructInstanceId); | |
5668 } | |
5669 | |
5670 // DO NOT DELETE THOSE! | |
5671 OrthancStone::DicomStructureSet* normalContent = normalStructLoader->GetContent(); | |
5672 OrthancStone::DicomStructureSet* optimizedContent = optimizedStructLoader->GetContent(); | |
5673 | |
5674 EXPECT_EQ(normalContent->GetStructuresCount(), optimizedContent->GetStructuresCount()); | |
5675 | |
5676 for (size_t i = 0; i < normalContent->GetStructuresCount(); ++i) | |
5677 { | |
5678 Vector structureCenter1 = normalContent->GetStructureCenter(i); | |
5679 const std::string& structureName1 = normalContent->GetStructureName(i); | |
5680 const std::string& structureInterpretation1 = normalContent->GetStructureInterpretation(i); | |
5681 Color structureColor1 = normalContent->GetStructureColor(i); | |
5682 | |
5683 Vector structureCenter2 = optimizedContent->GetStructureCenter(i); | |
5684 const std::string& structureName2 = optimizedContent->GetStructureName(i); | |
5685 const std::string& structureInterpretation2 = optimizedContent->GetStructureInterpretation(i); | |
5686 Color structureColor2 = optimizedContent->GetStructureColor(i); | |
5687 | |
5688 EXPECT_NEAR(structureCenter1[0], structureCenter2[0], TOLERANCE); | |
5689 EXPECT_NEAR(structureCenter1[1], structureCenter2[1], TOLERANCE); | |
5690 EXPECT_NEAR(structureCenter1[2], structureCenter2[2], TOLERANCE); | |
5691 | |
5692 EXPECT_EQ(structureName1, structureName2); | |
5693 EXPECT_EQ(structureInterpretation1, structureInterpretation2); | |
5694 EXPECT_EQ(structureColor1.GetRed(), structureColor2.GetRed()); | |
5695 EXPECT_EQ(structureColor1.GetGreen(), structureColor2.GetGreen()); | |
5696 EXPECT_EQ(structureColor1.GetBlue(), structureColor2.GetBlue()); | |
5697 } | |
5698 } |