comparison OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp @ 2099:67db5afb305d

partial integration dicom-sr->mainline
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 08 Nov 2023 17:26:22 +0100
parents 7c3d65166c26
children 129cb165ea8d c23eef785569
comparison
equal deleted inserted replaced
2095:ec676dbe85ac 2099:67db5afb305d
116 } 116 }
117 117
118 118
119 namespace OrthancStone 119 namespace OrthancStone
120 { 120 {
121 void DicomStructuredReport::ReferencedInstance::AddFrame(unsigned int frame) 121 void DicomStructuredReport::Structure::Copy(const Structure& other)
122 { 122 {
123 if (frame == 0) 123 if (other.HasFrameNumber())
124 {
125 SetFrameNumber(other.GetFrameNumber());
126 }
127
128 if (other.HasProbabilityOfCancer())
129 {
130 SetProbabilityOfCancer(other.GetProbabilityOfCancer());
131 }
132 }
133
134
135 DicomStructuredReport::Structure::Structure(const std::string& sopInstanceUid) :
136 sopInstanceUid_(sopInstanceUid),
137 hasFrameNumber_(false),
138 hasProbabilityOfCancer_(false)
139 {
140 }
141
142
143 void DicomStructuredReport::Structure::SetFrameNumber(unsigned int frame)
144 {
145 hasFrameNumber_ = true;
146 frameNumber_ = frame;
147 }
148
149
150 void DicomStructuredReport::Structure::SetProbabilityOfCancer(float probability)
151 {
152 if (probability < 0 ||
153 probability > 100)
124 { 154 {
125 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 155 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
126 } 156 }
127 else 157 else
128 { 158 {
129 frames_.insert(frame - 1); 159 hasProbabilityOfCancer_ = true;
130 } 160 probabilityOfCancer_ = probability;
131 } 161 }
132 162 }
133 163
134 class DicomStructuredReport::Structure : public boost::noncopyable 164
135 { 165 unsigned int DicomStructuredReport::Structure::GetFrameNumber() const
136 private: 166 {
137 std::string sopInstanceUid_; 167 if (hasFrameNumber_)
138 bool hasFrameNumber_; 168 {
139 unsigned int frameNumber_; 169 return frameNumber_;
140 bool hasProbabilityOfCancer_; 170 }
141 float probabilityOfCancer_; 171 else
142 172 {
143 public: 173 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
144 Structure(const std::string& sopInstanceUid) : 174 }
145 sopInstanceUid_(sopInstanceUid), 175 }
146 hasFrameNumber_(false), 176
147 hasProbabilityOfCancer_(false) 177 float DicomStructuredReport::Structure::GetProbabilityOfCancer() const
148 { 178 {
149 } 179 if (hasProbabilityOfCancer_)
150 180 {
151 virtual ~Structure() 181 return probabilityOfCancer_;
152 { 182 }
153 } 183 else
154 184 {
155 void SetFrameNumber(unsigned int frame) 185 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
156 { 186 }
157 if (frame <= 0) 187 }
158 { 188
159 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 189
160 } 190 DicomStructuredReport::Point::Point(const std::string& sopInstanceUid,
161 else 191 double x,
162 { 192 double y) :
163 hasFrameNumber_ = true; 193 Structure(sopInstanceUid),
164 frameNumber_ = frame - 1; 194 point_(x, y)
165 } 195 {
166 } 196 }
167 197
168 void SetProbabilityOfCancer(float probability) 198
169 { 199 DicomStructuredReport::Structure* DicomStructuredReport::Point::Clone() const
170 if (probability < 0 || 200 {
171 probability > 100) 201 std::unique_ptr<Point> cloned(new Point(GetSopInstanceUid(), point_.GetX(), point_.GetY()));
172 { 202 cloned->Copy(*this);
173 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 203 return cloned.release();
174 } 204 }
175 else 205
176 { 206
177 hasProbabilityOfCancer_ = true; 207 DicomStructuredReport::Polyline::Polyline(const std::string& sopInstanceUid,
178 probabilityOfCancer_ = probability; 208 const float* points,
179 } 209 unsigned long pointsCount) :
180 } 210 Structure(sopInstanceUid)
181 211 {
182 bool HasFrameNumber() const 212 if (pointsCount % 2 != 0)
183 { 213 {
184 return hasFrameNumber_; 214 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
185 } 215 }
186 216
187 bool HasProbabilityOfCancer() const 217 points_.reserve(pointsCount / 2);
188 { 218
189 return hasProbabilityOfCancer_; 219 for (unsigned long i = 0; i < pointsCount; i += 2)
190 } 220 {
191 221 points_.push_back(ScenePoint2D(points[i], points[i + 1]));
192 unsigned int GetFrameNumber() const 222 }
193 { 223 }
194 if (hasFrameNumber_) 224
195 { 225
196 return frameNumber_; 226 DicomStructuredReport::Polyline::Polyline(const std::string& sopInstanceUid,
197 } 227 const std::vector<ScenePoint2D>& points) :
198 else 228 Structure(sopInstanceUid),
199 { 229 points_(points)
200 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 230 {
201 } 231 }
202 } 232
203 233
204 float GetProbabilityOfCancer() const 234 DicomStructuredReport::Structure* DicomStructuredReport::Polyline::Clone() const
205 { 235 {
206 if (hasProbabilityOfCancer_) 236 std::unique_ptr<Polyline> cloned(new Polyline(GetSopInstanceUid(), points_));
207 { 237 cloned->Copy(*this);
208 return probabilityOfCancer_; 238 return cloned.release();
209 } 239 }
210 else 240
211 { 241
212 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 242 const ScenePoint2D& DicomStructuredReport::Polyline::GetPoint(size_t i) const
213 } 243 {
214 } 244 if (i >= points_.size())
215 }; 245 {
216 246 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
217 247 }
218 class DicomStructuredReport::Point : public Structure 248 else
219 { 249 {
220 private: 250 return points_[i];
221 ScenePoint2D point_; 251 }
222 252 }
223 public:
224 Point(const std::string& sopInstanceUid,
225 double x,
226 double y) :
227 Structure(sopInstanceUid),
228 point_(x, y)
229 {
230 }
231
232 const ScenePoint2D& GetPoint() const
233 {
234 return point_;
235 }
236 };
237
238
239 class DicomStructuredReport::Polyline : public Structure
240 {
241 private:
242 std::vector<ScenePoint2D> points_;
243
244 public:
245 Polyline(const std::string& sopInstanceUid,
246 const float* points,
247 unsigned long pointsCount) :
248 Structure(sopInstanceUid)
249 {
250 if (pointsCount % 2 != 0)
251 {
252 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
253 }
254
255 points_.reserve(pointsCount / 2);
256
257 for (unsigned long i = 0; i < pointsCount; i += 2)
258 {
259 points_.push_back(ScenePoint2D(points[i], points[i + 1]));
260 }
261 }
262
263 size_t GetSize() const
264 {
265 return points_.size();
266 }
267
268 const ScenePoint2D& GetPoint(size_t i) const
269 {
270 if (i >= points_.size())
271 {
272 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
273 }
274 else
275 {
276 return points_[i];
277 }
278 }
279 };
280 253
281 254
282 void DicomStructuredReport::AddStructure(const std::string& sopInstanceUid, 255 void DicomStructuredReport::AddStructure(const std::string& sopInstanceUid,
283 DcmItem& group, 256 DcmItem& group,
284 bool hasFrameNumber, 257 bool hasFrameNumber,
502 Orthanc::Toolbox::SplitString(tokens, frames, '\\'); 475 Orthanc::Toolbox::SplitString(tokens, frames, '\\');
503 476
504 for (size_t m = 0; m < tokens.size(); m++) 477 for (size_t m = 0; m < tokens.size(); m++)
505 { 478 {
506 uint32_t frame; 479 uint32_t frame;
507 if (!Orthanc::SerializationToolbox::ParseUnsignedInteger32(frame, tokens[m])) 480 if (!Orthanc::SerializationToolbox::ParseUnsignedInteger32(frame, tokens[m]) ||
481 frame <= 0)
508 { 482 {
509 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 483 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
510 } 484 }
511 else 485 else
512 { 486 {
513 AddStructure(sopInstanceUid, group, true, frame, hasProbabilityOfCancer, probabilityOfCancer); 487 AddStructure(sopInstanceUid, group, true, frame - 1, hasProbabilityOfCancer, probabilityOfCancer);
514 instanceInformation->second->AddFrame(frame); 488 instanceInformation->second->AddFrame(frame - 1);
515 } 489 }
516 } 490 }
517 } 491 }
518 else 492 else
519 { 493 {
520 AddStructure(sopInstanceUid, group, false, 0, hasProbabilityOfCancer, probabilityOfCancer); 494 AddStructure(sopInstanceUid, group, false, 0, hasProbabilityOfCancer, probabilityOfCancer);
521 instanceInformation->second->AddFrame(1); 495 instanceInformation->second->AddFrame(0);
522 } 496 }
523 } 497 }
524 } 498 }
525 } 499 }
526 } 500 }
529 } 503 }
530 } 504 }
531 } 505 }
532 506
533 507
508 DicomStructuredReport::DicomStructuredReport(const DicomStructuredReport& other) :
509 studyInstanceUid_(other.studyInstanceUid_),
510 seriesInstanceUid_(other.seriesInstanceUid_),
511 sopInstanceUid_(other.sopInstanceUid_),
512 orderedInstances_(other.orderedInstances_)
513 {
514 for (std::map<std::string, ReferencedInstance*>::const_iterator
515 it = other.instancesInformation_.begin(); it != other.instancesInformation_.end(); ++it)
516 {
517 assert(it->second != NULL);
518 instancesInformation_[it->first] = new ReferencedInstance(*it->second);
519 }
520
521 for (std::deque<Structure*>::const_iterator it = other.structures_.begin(); it != other.structures_.end(); ++it)
522 {
523 assert(*it != NULL);
524 structures_.push_back((*it)->Clone());
525 }
526 }
527
528
534 DicomStructuredReport::~DicomStructuredReport() 529 DicomStructuredReport::~DicomStructuredReport()
535 { 530 {
536 for (std::list<Structure*>::iterator it = structures_.begin(); it != structures_.end(); ++it) 531 for (std::deque<Structure*>::iterator it = structures_.begin(); it != structures_.end(); ++it)
537 { 532 {
538 assert(*it != NULL); 533 assert(*it != NULL);
539 delete *it; 534 delete *it;
540 } 535 }
541 536
596 orderedInstances_[i], 591 orderedInstances_[i],
597 found->second->GetSopClassUid(), *frame)); 592 found->second->GetSopClassUid(), *frame));
598 } 593 }
599 } 594 }
600 } 595 }
601 } 596
597
598 const DicomStructuredReport::Structure& DicomStructuredReport::GetStructure(size_t index) const
599 {
600 if (index >= structures_.size())
601 {
602 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
603 }
604 else
605 {
606 assert(structures_[index] != NULL);
607 return *structures_[index];
608 }
609 }
610 }