comparison Framework/Loaders/DicomStructureSetLoader.cpp @ 1416:d959bc8f6c1b loader-injection-feature

Instance lookup is now performed in a separate class through an interface. Another implementation can be injected (SetInstanceLookupHandler)
author Benjamin Golinvaux <bgo@osimis.io>
date Mon, 11 May 2020 17:37:30 +0200
parents ffe9beb7c5d3
children 30deba7bc8e2
comparison
equal deleted inserted replaced
1415:998697c5ec74 1416:d959bc8f6c1b
46 o << val; 46 o << val;
47 //return o; 47 //return o;
48 } 48 }
49 #endif 49 #endif
50 50
51 51 // implementation of IInstanceLookupHandler that uses Orthanc REST API calls to retrive the
52 class DicomStructureSetLoader::AddReferencedInstance : public LoaderStateMachine::State 52 // geometry of referenced instances
53 class DicomStructureSetLoader::RestInstanceLookupHandler : public DicomStructureSetLoader::IInstanceLookupHandler,
54 public LoaderStateMachine
55 {
56 public:
57 static boost::shared_ptr<RestInstanceLookupHandler > Create(DicomStructureSetLoader& loader)
58 {
59 boost::shared_ptr<RestInstanceLookupHandler> obj(new RestInstanceLookupHandler(loader));
60 obj->LoaderStateMachine::PostConstructor();
61 return obj;
62 }
63
64 protected:
65 RestInstanceLookupHandler(DicomStructureSetLoader& loader)
66 : LoaderStateMachine(loader.loadersContext_)
67 , loader_(loader)
68 {
69 }
70
71 virtual void RetrieveReferencedSlices(const std::set<std::string>& nonEmptyInstances) ORTHANC_OVERRIDE;
72
73 private:
74 // these subclasses hold the loading state
75 class AddReferencedInstance; // 2nd state
76 class LookupInstance; // 1st state
77
78 DicomStructureSetLoader& loader_;
79 };
80
81 class DicomStructureSetLoader::RestInstanceLookupHandler::AddReferencedInstance : public LoaderStateMachine::State
53 { 82 {
54 private: 83 private:
55 std::string instanceId_; 84 std::string instanceId_;
56 85
57 public: 86 public:
69 98
70 Orthanc::DicomMap dicom; 99 Orthanc::DicomMap dicom;
71 dicom.FromDicomAsJson(tags); 100 dicom.FromDicomAsJson(tags);
72 101
73 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); 102 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>();
74 103
75 loader.content_->AddReferencedSlice(dicom); 104 loader.AddReferencedSlice(dicom);
76 loader.countProcessedInstances_ ++;
77 assert(loader.countProcessedInstances_ <= loader.countReferencedInstances_);
78
79 loader.revision_++;
80 loader.SetStructuresUpdated();
81
82 if (loader.countProcessedInstances_ == loader.countReferencedInstances_)
83 {
84 // All the referenced instances have been loaded, finalize the RT-STRUCT
85 loader.content_->CheckReferencedSlices();
86 loader.revision_++;
87 loader.SetStructuresReady();
88 }
89 } 105 }
90 }; 106 };
91 107
92 108
93 // State that converts a "SOP Instance UID" to an Orthanc identifier 109 // State that converts a "SOP Instance UID" to an Orthanc identifier
94 class DicomStructureSetLoader::LookupInstance : public LoaderStateMachine::State 110 class DicomStructureSetLoader::RestInstanceLookupHandler::LookupInstance : public LoaderStateMachine::State
95 { 111 {
96 private: 112 private:
97 std::string sopInstanceUid_; 113 std::string sopInstanceUid_;
98 114
99 public: 115 public:
104 { 120 {
105 } 121 }
106 122
107 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) 123 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message)
108 { 124 {
109 #if 0
110 LOG(TRACE) << "DicomStructureSetLoader::LookupInstance::Handle() (SUCCESS)";
111 #endif
112 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); 125 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>();
113 126
114 Json::Value lookup; 127 Json::Value lookup;
115 message.ParseJsonBody(lookup); 128 message.ParseJsonBody(lookup);
116 129
145 Schedule(command.release()); 158 Schedule(command.release());
146 } 159 }
147 } 160 }
148 }; 161 };
149 162
163 void DicomStructureSetLoader::RestInstanceLookupHandler::RetrieveReferencedSlices(
164 const std::set<std::string>& nonEmptyInstances)
165 {
166 for (std::set<std::string>::const_iterator it = nonEmptyInstances.begin();
167 it != nonEmptyInstances.end();
168 ++it)
169 {
170 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand);
171 command->SetUri("/tools/lookup");
172 command->SetMethod(Orthanc::HttpMethod_Post);
173 command->SetBody(*it);
174 command->AcquirePayload(new LookupInstance(loader_, *it));
175 Schedule(command.release());
176 }
177 }
150 178
151 class DicomStructureSetLoader::LoadStructure : public LoaderStateMachine::State 179 class DicomStructureSetLoader::LoadStructure : public LoaderStateMachine::State
152 { 180 {
153 public: 181 public:
154 LoadStructure(DicomStructureSetLoader& that) : 182 LoadStructure(DicomStructureSetLoader& that) :
157 } 185 }
158 186
159 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) 187 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message)
160 { 188 {
161 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); 189 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>();
162 190
191 // Set the actual structure set content
163 { 192 {
164 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); 193 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer());
194
165 loader.content_.reset(new OrthancStone::DicomStructureSet(dicom)); 195 loader.content_.reset(new OrthancStone::DicomStructureSet(dicom));
166 size_t structureCount = loader.content_->GetStructuresCount(); 196 }
167 loader.structureVisibility_.resize(structureCount); 197
168 bool everythingVisible = false; 198 // initialize visibility flags
169 if ((loader.initiallyVisibleStructures_.size() == 1) 199 SetDefaultStructureVisibility();
170 && (loader.initiallyVisibleStructures_[0].size() == 1) 200
171 && (loader.initiallyVisibleStructures_[0][0] == '*')) 201 // retrieve the (non-empty) referenced instances (the CT slices containing the corresponding structures)
172 {
173 everythingVisible = true;
174 }
175
176 for (size_t i = 0; i < structureCount; ++i)
177 {
178 // if a single "*" string is supplied, this means we want everything
179 // to be visible...
180 if(everythingVisible)
181 {
182 loader.structureVisibility_.at(i) = true;
183 }
184 else
185 {
186 // otherwise, we only enable visibility for those structures whose
187 // names are mentioned in the initiallyVisibleStructures_ array
188 const std::string& structureName = loader.content_->GetStructureName(i);
189
190 std::vector<std::string>::iterator foundIt =
191 std::find(
192 loader.initiallyVisibleStructures_.begin(),
193 loader.initiallyVisibleStructures_.end(),
194 structureName);
195 std::vector<std::string>::iterator endIt = loader.initiallyVisibleStructures_.end();
196 if (foundIt != endIt)
197 loader.structureVisibility_.at(i) = true;
198 else
199 loader.structureVisibility_.at(i) = false;
200 }
201 }
202 }
203
204 // Some (admittedly invalid) Dicom files have empty values in the 202 // Some (admittedly invalid) Dicom files have empty values in the
205 // 0008,1155 tag. We try our best to cope with this. 203 // 0008,1155 tag. We try our best to cope with this.
204 // this is why we use `nonEmptyInstances` and not `instances`
206 std::set<std::string> instances; 205 std::set<std::string> instances;
207 std::set<std::string> nonEmptyInstances; 206 std::set<std::string> nonEmptyInstances;
207
208 // this traverses the polygon collection for all structures and retrieve the SOPInstanceUID of
209 // the referenced instances
208 loader.content_->GetReferencedInstances(instances); 210 loader.content_->GetReferencedInstances(instances);
211
209 for (std::set<std::string>::const_iterator 212 for (std::set<std::string>::const_iterator
210 it = instances.begin(); it != instances.end(); ++it) 213 it = instances.begin(); it != instances.end(); ++it)
211 { 214 {
212 std::string instance = Orthanc::Toolbox::StripSpaces(*it); 215 std::string instance = Orthanc::Toolbox::StripSpaces(*it);
213 if(instance != "") 216 if(instance != "")
214 nonEmptyInstances.insert(instance); 217 nonEmptyInstances.insert(instance);
215 } 218 }
216 219
217 loader.countReferencedInstances_ = 220 loader.RetrieveReferencedSlices(nonEmptyInstances);
218 static_cast<unsigned int>(nonEmptyInstances.size()); 221 }
219 222
220 for (std::set<std::string>::const_iterator 223 void SetDefaultStructureVisibility()
221 it = nonEmptyInstances.begin(); it != nonEmptyInstances.end(); ++it) 224 {
222 { 225 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>();
223 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); 226
224 command->SetUri("/tools/lookup"); 227 size_t structureCount = loader.content_->GetStructuresCount();
225 command->SetMethod(Orthanc::HttpMethod_Post); 228
226 command->SetBody(*it); 229 loader.structureVisibility_.resize(structureCount);
227 command->AcquirePayload(new LookupInstance(loader, *it)); 230 bool everythingVisible = false;
228 Schedule(command.release()); 231 if ((loader.initiallyVisibleStructures_.size() == 1)
229 } 232 && (loader.initiallyVisibleStructures_[0].size() == 1)
230 } 233 && (loader.initiallyVisibleStructures_[0][0] == '*'))
234 {
235 everythingVisible = true;
236 }
237
238 for (size_t i = 0; i < structureCount; ++i)
239 {
240 // if a single "*" string is supplied, this means we want everything
241 // to be visible...
242 if (everythingVisible)
243 {
244 loader.structureVisibility_.at(i) = true;
245 }
246 else
247 {
248 // otherwise, we only enable visibility for those structures whose
249 // names are mentioned in the initiallyVisibleStructures_ array
250 const std::string& structureName = loader.content_->GetStructureName(i);
251
252 std::vector<std::string>::iterator foundIt =
253 std::find(
254 loader.initiallyVisibleStructures_.begin(),
255 loader.initiallyVisibleStructures_.end(),
256 structureName);
257 std::vector<std::string>::iterator endIt = loader.initiallyVisibleStructures_.end();
258 if (foundIt != endIt)
259 loader.structureVisibility_.at(i) = true;
260 else
261 loader.structureVisibility_.at(i) = false;
262 }
263 }
264 }
265
266 private:
267
268
231 }; 269 };
232 270
233 271
234 class DicomStructureSetLoader::Slice : public IExtractedSlice 272 class DicomStructureSetLoader::Slice : public IExtractedSlice
235 { 273 {
345 , revision_(0) 383 , revision_(0)
346 , countProcessedInstances_(0) 384 , countProcessedInstances_(0)
347 , countReferencedInstances_(0) 385 , countReferencedInstances_(0)
348 , structuresReady_(false) 386 , structuresReady_(false)
349 { 387 {
350 } 388 // the default handler to retrieve slice geometry is RestInstanceLookupHandler
351 389 instanceLookupHandler_ = RestInstanceLookupHandler::Create(*this);
390 }
352 391
353 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> DicomStructureSetLoader::Create(OrthancStone::ILoadersContext& loadersContext) 392 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> DicomStructureSetLoader::Create(OrthancStone::ILoadersContext& loadersContext)
354 { 393 {
355 boost::shared_ptr<DicomStructureSetLoader> obj( 394 boost::shared_ptr<DicomStructureSetLoader> obj(
356 new DicomStructureSetLoader( 395 new DicomStructureSetLoader(
357 loadersContext)); 396 loadersContext));
358 obj->LoaderStateMachine::PostConstructor(); 397 obj->LoaderStateMachine::PostConstructor();
359 return obj; 398 return obj;
360 399 }
400
401 void DicomStructureSetLoader::AddReferencedSlice(const Orthanc::DicomMap& dicom)
402 {
403 content_->AddReferencedSlice(dicom);
404 countProcessedInstances_ ++;
405 assert(countProcessedInstances_ <= countReferencedInstances_);
406
407 revision_++;
408 SetStructuresUpdated();
409
410 if (countProcessedInstances_ == countReferencedInstances_)
411 {
412 // All the referenced instances have been loaded, finalize the RT-STRUCT
413 content_->CheckReferencedSlices();
414 revision_++;
415 SetStructuresReady();
416 }
417 }
418
419 void DicomStructureSetLoader::RetrieveReferencedSlices(const std::set<std::string>& nonEmptyInstances)
420 {
421 // we set the number of referenced instances. This allows to know, in the method above, when we're done
422 countReferencedInstances_ = static_cast<unsigned int>(nonEmptyInstances.size());
423 instanceLookupHandler_->RetrieveReferencedSlices(nonEmptyInstances);
361 } 424 }
362 425
363 void DicomStructureSetLoader::SetStructureDisplayState(size_t structureIndex, bool display) 426 void DicomStructureSetLoader::SetStructureDisplayState(size_t structureIndex, bool display)
364 { 427 {
365 structureVisibility_.at(structureIndex) = display; 428 structureVisibility_.at(structureIndex) = display;