comparison OrthancServer/SliceOrdering.cpp @ 1703:b80e76dd1d56 db-changes

ordered-slices continued
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 13 Oct 2015 16:10:35 +0200
parents 9980875edc7c
children ec66a16aa398
comparison
equal deleted inserted replaced
1702:9980875edc7c 1703:b80e76dd1d56
31 31
32 32
33 #include "PrecompiledHeadersServer.h" 33 #include "PrecompiledHeadersServer.h"
34 #include "SliceOrdering.h" 34 #include "SliceOrdering.h"
35 35
36 #include "../Core/Logging.h"
36 #include "../Core/Toolbox.h" 37 #include "../Core/Toolbox.h"
37 38 #include "ServerEnumerations.h"
39
40 #include <algorithm>
38 #include <boost/lexical_cast.hpp> 41 #include <boost/lexical_cast.hpp>
42 #include <boost/noncopyable.hpp>
39 43
40 44
41 namespace Orthanc 45 namespace Orthanc
42 { 46 {
43 static bool TokenizeVector(std::vector<float>& result, 47 static bool TokenizeVector(std::vector<float>& result,
87 return TokenizeVector(result, value->AsString(), expectedSize); 91 return TokenizeVector(result, value->AsString(), expectedSize);
88 } 92 }
89 } 93 }
90 94
91 95
92 struct SliceOrdering::Instance 96 struct SliceOrdering::Instance : public boost::noncopyable
93 { 97 {
98 private:
94 std::string instanceId_; 99 std::string instanceId_;
95 bool hasPosition_; 100 bool hasPosition_;
96 Vector position_; 101 Vector position_;
97 bool hasIndexInSeries_; 102 bool hasIndexInSeries_;
98 size_t indexInSeries_; 103 size_t indexInSeries_;
99 104 unsigned int framesCount_;
105
106 public:
100 Instance(ServerIndex& index, 107 Instance(ServerIndex& index,
101 const std::string& instanceId) : 108 const std::string& instanceId) :
102 instanceId_(instanceId) 109 instanceId_(instanceId),
110 framesCount_(1)
103 { 111 {
104 DicomMap instance; 112 DicomMap instance;
105 if (!index.GetMainDicomTags(instance, instanceId, ResourceType_Instance, ResourceType_Instance)) 113 if (!index.GetMainDicomTags(instance, instanceId, ResourceType_Instance, ResourceType_Instance))
106 { 114 {
107 throw OrthancException(ErrorCode_UnknownResource); 115 throw OrthancException(ErrorCode_UnknownResource);
116 }
117
118 const DicomValue* frames = instance.TestAndGetValue(DICOM_TAG_NUMBER_OF_FRAMES);
119 if (frames != NULL &&
120 !frames->IsNull())
121 {
122 try
123 {
124 framesCount_ = boost::lexical_cast<unsigned int>(frames->AsString());
125 }
126 catch (boost::bad_lexical_cast&)
127 {
128 }
108 } 129 }
109 130
110 std::vector<float> tmp; 131 std::vector<float> tmp;
111 hasPosition_ = TokenizeVector(tmp, instance, DICOM_TAG_IMAGE_POSITION_PATIENT, 3); 132 hasPosition_ = TokenizeVector(tmp, instance, DICOM_TAG_IMAGE_POSITION_PATIENT, 3);
112 133
130 } 151 }
131 catch (boost::bad_lexical_cast&) 152 catch (boost::bad_lexical_cast&)
132 { 153 {
133 } 154 }
134 } 155 }
156
157 const std::string& GetIdentifier() const
158 {
159 return instanceId_;
160 }
161
162 bool HasPosition() const
163 {
164 return hasPosition_;
165 }
166
167 float ComputeRelativePosition(const Vector& normal) const
168 {
169 assert(HasPosition());
170 return (normal[0] * position_[0] +
171 normal[1] * position_[1] +
172 normal[2] * position_[2]);
173 }
174
175 bool HasIndexInSeries() const
176 {
177 return hasIndexInSeries_;
178 }
179
180 size_t GetIndexInSeries() const
181 {
182 assert(HasIndexInSeries());
183 return indexInSeries_;
184 }
185
186 unsigned int GetFramesCount() const
187 {
188 return framesCount_;
189 }
135 }; 190 };
191
192
193 class SliceOrdering::PositionComparator
194 {
195 private:
196 const Vector& normal_;
197
198 public:
199 PositionComparator(const Vector& normal) : normal_(normal)
200 {
201 }
202
203 int operator() (const Instance* a,
204 const Instance* b) const
205 {
206 return a->ComputeRelativePosition(normal_) < b->ComputeRelativePosition(normal_);
207 }
208 };
209
210
211 bool SliceOrdering::IndexInSeriesComparator(const SliceOrdering::Instance* a,
212 const SliceOrdering::Instance* b)
213 {
214 return a->GetIndexInSeries() < b->GetIndexInSeries();
215 }
136 216
137 217
138 void SliceOrdering::ComputeNormal() 218 void SliceOrdering::ComputeNormal()
139 { 219 {
140 DicomMap series; 220 DicomMap series;
169 } 249 }
170 250
171 251
172 bool SliceOrdering::SortUsingPositions() 252 bool SliceOrdering::SortUsingPositions()
173 { 253 {
254 if (instances_.size() <= 1)
255 {
256 // One single instance: It is sorted by default
257 return true;
258 }
259
174 if (!hasNormal_) 260 if (!hasNormal_)
175 { 261 {
176 return false; 262 return false;
177 } 263 }
178 264
179 for (size_t i = 0; i < instances_.size(); i++) 265 for (size_t i = 0; i < instances_.size(); i++)
180 { 266 {
181 assert(instances_[i] != NULL); 267 assert(instances_[i] != NULL);
182 if (!instances_[i]->hasPosition_) 268 if (!instances_[i]->HasPosition())
183 { 269 {
184 return false; 270 return false;
185 } 271 }
186 } 272 }
187 273
274 PositionComparator comparator(normal_);
275 std::sort(instances_.begin(), instances_.end(), comparator);
276
277 float a = instances_.front()->ComputeRelativePosition(normal_);
278 float b = instances_.back()->ComputeRelativePosition(normal_);
279
280 if (std::fabs(b - a) <= 10.0f * std::numeric_limits<float>::epsilon())
281 {
282 // Not enough difference between the minimum and maximum
283 // positions along the normal of the volume
284 return false;
285 }
286 else
287 {
288 // This is a 3D volume
289 isVolume_ = true;
290 return true;
291 }
292 }
293
294
295 bool SliceOrdering::SortUsingIndexInSeries()
296 {
297 if (instances_.size() <= 1)
298 {
299 // One single instance: It is sorted by default
300 return true;
301 }
302
303 for (size_t i = 0; i < instances_.size(); i++)
304 {
305 assert(instances_[i] != NULL);
306 if (!instances_[i]->HasIndexInSeries())
307 {
308 return false;
309 }
310 }
311
312 std::sort(instances_.begin(), instances_.end(), IndexInSeriesComparator);
188 313
314 for (size_t i = 1; i < instances_.size(); i++)
315 {
316 if (instances_[i - 1]->GetIndexInSeries() == instances_[i]->GetIndexInSeries())
317 {
318 // The current "IndexInSeries" occurs 2 times: Not a proper ordering
319 return false;
320 }
321 }
189 322
190 return true; 323 return true;
191 } 324 }
192 325
193 326
194 SliceOrdering::SliceOrdering(ServerIndex& index, 327 SliceOrdering::SliceOrdering(ServerIndex& index,
195 const std::string& seriesId) : 328 const std::string& seriesId) :
196 index_(index), 329 index_(index),
197 seriesId_(seriesId) 330 seriesId_(seriesId),
331 isVolume_(false)
198 { 332 {
199 ComputeNormal(); 333 ComputeNormal();
200 CreateInstances(); 334 CreateInstances();
335
336 if (!SortUsingPositions() &&
337 !SortUsingIndexInSeries())
338 {
339 LOG(ERROR) << "Unable to order the slices of the series " << seriesId;
340 throw OrthancException(ErrorCode_CannotOrderSlices);
341 }
201 } 342 }
202 343
203 344
204 SliceOrdering::~SliceOrdering() 345 SliceOrdering::~SliceOrdering()
205 { 346 {
210 { 351 {
211 delete *it; 352 delete *it;
212 } 353 }
213 } 354 }
214 } 355 }
356
357
358 const std::string& SliceOrdering::GetInstanceId(size_t index) const
359 {
360 if (index >= instances_.size())
361 {
362 throw OrthancException(ErrorCode_ParameterOutOfRange);
363 }
364 else
365 {
366 return instances_[index]->GetIdentifier();
367 }
368 }
369
370
371 unsigned int SliceOrdering::GetFramesCount(size_t index) const
372 {
373 if (index >= instances_.size())
374 {
375 throw OrthancException(ErrorCode_ParameterOutOfRange);
376 }
377 else
378 {
379 return instances_[index]->GetFramesCount();
380 }
381 }
382
383
384 void SliceOrdering::Format(Json::Value& result) const
385 {
386 result = Json::objectValue;
387 result["Type"] = (isVolume_ ? "Volume" : "Sequence");
388
389 Json::Value tmp = Json::arrayValue;
390 for (size_t i = 0; i < GetInstancesCount(); i++)
391 {
392 tmp.append(GetBasePath(ResourceType_Instance, GetInstanceId(i)) + "/file");
393 }
394
395 result["Dicom"] = tmp;
396
397 tmp.clear();
398 for (size_t i = 0; i < GetInstancesCount(); i++)
399 {
400 std::string base = GetBasePath(ResourceType_Instance, GetInstanceId(i));
401 for (size_t j = 0; j < GetFramesCount(i); j++)
402 {
403 tmp.append(base + "/frames/" + boost::lexical_cast<std::string>(j));
404 }
405 }
406
407 result["Slices"] = tmp;
408 }
215 } 409 }