Mercurial > hg > orthanc-stone
comparison Framework/Radiography/RadiographyScene.cpp @ 421:f87f28624b96 cache-in-radiography
tentative to make SmartLoader and RadiographyScene work together (not really working)
author | am@osimis.io |
---|---|
date | Tue, 20 Nov 2018 16:35:29 +0100 |
parents | c23df8b3433b |
children |
comparison
equal
deleted
inserted
replaced
420:8bf717c4e497 | 421:f87f28624b96 |
---|---|
53 assert(layer->second != NULL); | 53 assert(layer->second != NULL); |
54 layer_ = layer->second; | 54 layer_ = layer->second; |
55 } | 55 } |
56 } | 56 } |
57 | 57 |
58 | 58 |
59 RadiographyScene::LayerAccessor::LayerAccessor(RadiographyScene& scene, | 59 RadiographyScene::LayerAccessor::LayerAccessor(RadiographyScene& scene, |
60 double x, | 60 double x, |
61 double y) : | 61 double y) : |
62 scene_(scene), | 62 scene_(scene), |
63 index_(0) // Dummy initialization | 63 index_(0) // Dummy initialization |
64 { | 64 { |
65 if (scene.LookupLayer(index_, x, y)) | 65 if (scene.LookupLayer(index_, x, y)) |
66 { | 66 { |
67 Layers::iterator layer = scene.layers_.find(index_); | 67 Layers::iterator layer = scene.layers_.find(index_); |
68 | 68 |
69 if (layer == scene.layers_.end()) | 69 if (layer == scene.layers_.end()) |
70 { | 70 { |
71 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 71 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
72 } | 72 } |
73 else | 73 else |
117 } | 117 } |
118 else | 118 else |
119 { | 119 { |
120 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 120 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
121 } | 121 } |
122 } | 122 } |
123 | 123 |
124 | 124 |
125 | 125 |
126 class RadiographyScene::AlphaLayer : public RadiographyLayer | 126 class RadiographyScene::AlphaLayer : public RadiographyLayer |
127 { | 127 { |
143 void SetForegroundValue(float foreground) | 143 void SetForegroundValue(float foreground) |
144 { | 144 { |
145 useWindowing_ = false; | 145 useWindowing_ = false; |
146 foreground_ = foreground; | 146 foreground_ = foreground; |
147 } | 147 } |
148 | 148 |
149 | 149 |
150 void SetAlpha(Orthanc::ImageAccessor* image) | 150 void SetAlpha(Orthanc::ImageAccessor* image) |
151 { | 151 { |
152 std::auto_ptr<Orthanc::ImageAccessor> raii(image); | 152 std::auto_ptr<Orthanc::ImageAccessor> raii(image); |
153 | 153 |
154 if (image == NULL) | 154 if (image == NULL) |
155 { | 155 { |
156 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 156 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
157 } | 157 } |
158 | 158 |
168 | 168 |
169 void LoadText(const Orthanc::Font& font, | 169 void LoadText(const Orthanc::Font& font, |
170 const std::string& utf8) | 170 const std::string& utf8) |
171 { | 171 { |
172 SetAlpha(font.RenderAlpha(utf8)); | 172 SetAlpha(font.RenderAlpha(utf8)); |
173 } | 173 } |
174 | 174 |
175 | 175 |
176 virtual bool GetDefaultWindowing(float& center, | 176 virtual bool GetDefaultWindowing(float& center, |
177 float& width) const | 177 float& width) const |
178 { | 178 { |
179 return false; | 179 return false; |
180 } | 180 } |
181 | 181 |
182 | 182 |
183 virtual void Render(Orthanc::ImageAccessor& buffer, | 183 virtual void Render(Orthanc::ImageAccessor& buffer, |
184 const AffineTransform2D& viewTransform, | 184 const AffineTransform2D& viewTransform, |
185 ImageInterpolation interpolation) const | 185 ImageInterpolation interpolation) const |
186 { | 186 { |
187 if (alpha_.get() == NULL) | 187 if (alpha_.get() == NULL) |
188 { | 188 { |
189 return; | 189 return; |
190 } | 190 } |
191 | 191 |
192 if (buffer.GetFormat() != Orthanc::PixelFormat_Float32) | 192 if (buffer.GetFormat() != Orthanc::PixelFormat_Float32) |
193 { | 193 { |
194 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); | 194 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); |
195 } | 195 } |
196 | 196 |
197 unsigned int cropX, cropY, cropWidth, cropHeight; | 197 unsigned int cropX, cropY, cropWidth, cropHeight; |
198 GetCrop(cropX, cropY, cropWidth, cropHeight); | 198 GetCrop(cropX, cropY, cropWidth, cropHeight); |
199 | 199 |
200 const AffineTransform2D t = AffineTransform2D::Combine( | 200 const AffineTransform2D t = AffineTransform2D::Combine( |
201 viewTransform, GetTransform(), | 201 viewTransform, GetTransform(), |
202 AffineTransform2D::CreateOffset(cropX, cropY)); | 202 AffineTransform2D::CreateOffset(cropX, cropY)); |
203 | 203 |
204 Orthanc::ImageAccessor cropped; | 204 Orthanc::ImageAccessor cropped; |
205 alpha_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); | 205 alpha_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); |
206 | 206 |
207 Orthanc::Image tmp(Orthanc::PixelFormat_Grayscale8, buffer.GetWidth(), buffer.GetHeight(), false); | 207 Orthanc::Image tmp(Orthanc::PixelFormat_Grayscale8, buffer.GetWidth(), buffer.GetHeight(), false); |
208 | 208 |
209 t.Apply(tmp, cropped, interpolation, true /* clear */); | 209 t.Apply(tmp, cropped, interpolation, true /* clear */); |
210 | 210 |
211 // Blit | 211 // Blit |
212 const unsigned int width = buffer.GetWidth(); | 212 const unsigned int width = buffer.GetWidth(); |
213 const unsigned int height = buffer.GetHeight(); | 213 const unsigned int height = buffer.GetHeight(); |
214 | 214 |
215 float value = foreground_; | 215 float value = foreground_; |
216 | 216 |
217 if (useWindowing_) | 217 if (useWindowing_) |
218 { | 218 { |
219 float center, width; | 219 float center, width; |
220 if (scene_.GetWindowing(center, width)) | 220 if (scene_.GetWindowing(center, width)) |
221 { | 221 { |
222 value = center + width / 2.0f; | 222 value = center + width / 2.0f; |
223 } | 223 } |
224 } | 224 } |
225 | 225 |
226 for (unsigned int y = 0; y < height; y++) | 226 for (unsigned int y = 0; y < height; y++) |
227 { | 227 { |
228 float *q = reinterpret_cast<float*>(buffer.GetRow(y)); | 228 float *q = reinterpret_cast<float*>(buffer.GetRow(y)); |
229 const uint8_t *p = reinterpret_cast<uint8_t*>(tmp.GetRow(y)); | 229 const uint8_t *p = reinterpret_cast<uint8_t*>(tmp.GetRow(y)); |
230 | 230 |
231 for (unsigned int x = 0; x < width; x++, p++, q++) | 231 for (unsigned int x = 0; x < width; x++, p++, q++) |
232 { | 232 { |
233 float a = static_cast<float>(*p) / 255.0f; | 233 float a = static_cast<float>(*p) / 255.0f; |
234 | 234 |
235 *q = (a * value + (1.0f - a) * (*q)); | 235 *q = (a * value + (1.0f - a) * (*q)); |
236 } | 236 } |
237 } | 237 } |
238 } | 238 } |
239 | 239 |
240 | 240 |
241 virtual bool GetRange(float& minValue, | 241 virtual bool GetRange(float& minValue, |
242 float& maxValue) const | 242 float& maxValue) const |
243 { | 243 { |
244 if (useWindowing_) | 244 if (useWindowing_) |
245 { | 245 { |
262 | 262 |
263 return true; | 263 return true; |
264 } | 264 } |
265 } | 265 } |
266 }; | 266 }; |
267 | 267 |
268 | 268 |
269 | 269 |
270 class RadiographyScene::DicomLayer : public RadiographyLayer | 270 class RadiographyScene::DicomLayer : public RadiographyLayer |
271 { | 271 { |
272 private: | 272 private: |
273 std::auto_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData | 273 boost::shared_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData |
274 std::auto_ptr<DicomFrameConverter> converter_; | 274 std::auto_ptr<DicomFrameConverter> converter_; |
275 std::auto_ptr<Orthanc::ImageAccessor> converted_; // Float32 | 275 std::auto_ptr<Orthanc::ImageAccessor> converted_; // Float32 |
276 | 276 |
277 static OrthancPlugins::DicomTag ConvertTag(const Orthanc::DicomTag& tag) | 277 static OrthancPlugins::DicomTag ConvertTag(const Orthanc::DicomTag& tag) |
278 { | 278 { |
279 return OrthancPlugins::DicomTag(tag.GetGroup(), tag.GetElement()); | 279 return OrthancPlugins::DicomTag(tag.GetGroup(), tag.GetElement()); |
280 } | 280 } |
281 | 281 |
282 | 282 |
283 void ApplyConverter() | 283 void ApplyConverter() |
284 { | 284 { |
285 if (source_.get() != NULL && | 285 if (source_.get() != NULL && |
286 converter_.get() != NULL) | 286 converter_.get() != NULL) |
287 { | 287 { |
288 converted_.reset(converter_->ConvertFrame(*source_)); | 288 converted_.reset(converter_->ConvertFrame(*source_)); |
289 } | 289 } |
290 } | 290 } |
291 | 291 |
292 public: | 292 public: |
293 void SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset) | 293 void SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset) |
294 { | 294 { |
295 converter_.reset(new DicomFrameConverter); | 295 converter_.reset(new DicomFrameConverter); |
296 converter_->ReadParameters(dataset); | 296 converter_->ReadParameters(dataset); |
297 ApplyConverter(); | 297 ApplyConverter(); |
298 | 298 |
299 std::string tmp; | 299 std::string tmp; |
300 Vector pixelSpacing; | 300 Vector pixelSpacing; |
301 | 301 |
302 if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PIXEL_SPACING)) && | 302 if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PIXEL_SPACING)) && |
303 LinearAlgebra::ParseVector(pixelSpacing, tmp) && | 303 LinearAlgebra::ParseVector(pixelSpacing, tmp) && |
304 pixelSpacing.size() == 2) | 304 pixelSpacing.size() == 2) |
305 { | 305 { |
306 SetPixelSpacing(pixelSpacing[0], pixelSpacing[1]); | 306 SetPixelSpacing(pixelSpacing[0], pixelSpacing[1]); |
320 { | 320 { |
321 SetSize(width, height); | 321 SetSize(width, height); |
322 } | 322 } |
323 } | 323 } |
324 | 324 |
325 | 325 |
326 void SetSourceImage(Orthanc::ImageAccessor* image) // Takes ownership | 326 void SetSourceImage(boost::shared_ptr<Orthanc::ImageAccessor> image) |
327 { | 327 { |
328 std::auto_ptr<Orthanc::ImageAccessor> raii(image); | 328 if (image.get() == NULL) |
329 | |
330 if (image == NULL) | |
331 { | 329 { |
332 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 330 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
333 } | 331 } |
334 | 332 |
335 SetSize(image->GetWidth(), image->GetHeight()); | 333 SetSize(image->GetWidth(), image->GetHeight()); |
336 | 334 |
337 source_ = raii; | 335 source_ = image; |
338 ApplyConverter(); | 336 ApplyConverter(); |
339 } | 337 } |
340 | 338 |
341 | 339 |
342 virtual void Render(Orthanc::ImageAccessor& buffer, | 340 virtual void Render(Orthanc::ImageAccessor& buffer, |
343 const AffineTransform2D& viewTransform, | 341 const AffineTransform2D& viewTransform, |
344 ImageInterpolation interpolation) const | 342 ImageInterpolation interpolation) const |
345 { | 343 { |
346 if (converted_.get() != NULL) | 344 if (converted_.get() != NULL) |
352 | 350 |
353 unsigned int cropX, cropY, cropWidth, cropHeight; | 351 unsigned int cropX, cropY, cropWidth, cropHeight; |
354 GetCrop(cropX, cropY, cropWidth, cropHeight); | 352 GetCrop(cropX, cropY, cropWidth, cropHeight); |
355 | 353 |
356 AffineTransform2D t = AffineTransform2D::Combine( | 354 AffineTransform2D t = AffineTransform2D::Combine( |
357 viewTransform, GetTransform(), | 355 viewTransform, GetTransform(), |
358 AffineTransform2D::CreateOffset(cropX, cropY)); | 356 AffineTransform2D::CreateOffset(cropX, cropY)); |
359 | 357 |
360 Orthanc::ImageAccessor cropped; | 358 Orthanc::ImageAccessor cropped; |
361 converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); | 359 converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); |
362 | 360 |
363 t.Apply(buffer, cropped, interpolation, false); | 361 t.Apply(buffer, cropped, interpolation, false); |
409 { | 407 { |
410 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 408 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
411 } | 409 } |
412 | 410 |
413 std::auto_ptr<RadiographyLayer> raii(layer); | 411 std::auto_ptr<RadiographyLayer> raii(layer); |
414 | 412 |
415 size_t index = countLayers_++; | 413 size_t index = countLayers_++; |
416 raii->SetIndex(index); | 414 raii->SetIndex(index); |
417 layers_[index] = raii.release(); | 415 layers_[index] = raii.release(); |
418 | 416 |
419 EmitMessage(GeometryChangedMessage(*this)); | 417 EmitMessage(GeometryChangedMessage(*this)); |
420 EmitMessage(ContentChangedMessage(*this)); | 418 EmitMessage(ContentChangedMessage(*this)); |
421 | 419 |
422 return *layer; | 420 return *layer; |
423 } | 421 } |
424 | 422 |
425 | 423 |
426 RadiographyScene::RadiographyScene(MessageBroker& broker) : | 424 RadiographyScene::RadiographyScene(MessageBroker& broker) : |
427 IObserver(broker), | 425 IObserver(broker), |
428 IObservable(broker), | 426 IObservable(broker), |
429 countLayers_(0), | 427 countLayers_(0), |
487 alpha->LoadText(font, utf8); | 485 alpha->LoadText(font, utf8); |
488 | 486 |
489 return RegisterLayer(alpha.release()); | 487 return RegisterLayer(alpha.release()); |
490 } | 488 } |
491 | 489 |
492 | 490 |
493 RadiographyLayer& RadiographyScene::LoadTestBlock(unsigned int width, | 491 RadiographyLayer& RadiographyScene::LoadTestBlock(unsigned int width, |
494 unsigned int height) | 492 unsigned int height) |
495 { | 493 { |
496 std::auto_ptr<Orthanc::Image> block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false)); | 494 std::auto_ptr<Orthanc::Image> block(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, width, height, false)); |
497 | 495 |
518 alpha->SetAlpha(block.release()); | 516 alpha->SetAlpha(block.release()); |
519 | 517 |
520 return RegisterLayer(alpha.release()); | 518 return RegisterLayer(alpha.release()); |
521 } | 519 } |
522 | 520 |
523 | 521 |
524 RadiographyLayer& RadiographyScene::LoadDicomFrame(OrthancApiClient& orthanc, | 522 RadiographyLayer& RadiographyScene::LoadDicomFrame(OrthancApiClient& orthanc, |
525 const std::string& instance, | 523 const std::string& instance, |
526 unsigned int frame, | 524 unsigned int frame, |
527 bool httpCompression) | 525 bool httpCompression) |
528 { | 526 { |
529 RadiographyLayer& layer = RegisterLayer(new DicomLayer); | 527 RadiographyLayer& layer = RegisterLayer(new DicomLayer); |
530 | 528 |
531 { | 529 { |
532 IWebService::HttpHeaders headers; | 530 IWebService::HttpHeaders headers; |
533 std::string uri = "/instances/" + instance + "/tags"; | 531 std::string uri = "/instances/" + instance + "/tags"; |
534 | 532 |
535 orthanc.GetBinaryAsync( | 533 orthanc.GetBinaryAsync( |
536 uri, headers, | 534 uri, headers, |
537 new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> | 535 new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> |
538 (*this, &RadiographyScene::OnTagsReceived), NULL, | 536 (*this, &RadiographyScene::OnTagsReceived), NULL, |
539 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); | 537 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); |
540 } | 538 } |
541 | 539 |
542 { | 540 { |
543 IWebService::HttpHeaders headers; | 541 IWebService::HttpHeaders headers; |
544 headers["Accept"] = "image/x-portable-arbitrarymap"; | 542 headers["Accept"] = "image/x-portable-arbitrarymap"; |
545 | 543 |
546 if (httpCompression) | 544 if (httpCompression) |
547 { | 545 { |
548 headers["Accept-Encoding"] = "gzip"; | 546 headers["Accept-Encoding"] = "gzip"; |
549 } | 547 } |
550 | 548 |
551 std::string uri = ("/instances/" + instance + "/frames/" + | 549 std::string uri = ("/instances/" + instance + "/frames/" + |
552 boost::lexical_cast<std::string>(frame) + "/image-uint16"); | 550 boost::lexical_cast<std::string>(frame) + "/image-uint16"); |
553 | 551 |
554 orthanc.GetBinaryAsync( | 552 orthanc.GetBinaryAsync( |
555 uri, headers, | 553 uri, headers, |
556 new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> | 554 new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> |
557 (*this, &RadiographyScene::OnFrameReceived), NULL, | 555 (*this, &RadiographyScene::OnFrameReceived), NULL, |
558 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); | 556 new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); |
559 } | 557 } |
560 | 558 |
561 return layer; | 559 return layer; |
562 } | 560 } |
563 | 561 |
564 | 562 |
565 RadiographyLayer& RadiographyScene::LoadDicomWebFrame(IWebService& web) | 563 RadiographyLayer& RadiographyScene::LoadDicomWebFrame(IWebService& web) |
566 { | 564 { |
567 RadiographyLayer& layer = RegisterLayer(new DicomLayer); | 565 RadiographyLayer& layer = RegisterLayer(new DicomLayer); |
568 | 566 |
569 | 567 |
570 return layer; | 568 return layer; |
571 } | 569 } |
572 | 570 |
573 | 571 RadiographyLayer& RadiographyScene::SetFrame(IVolumeSlicer* slice) |
574 | 572 { |
575 void RadiographyScene::OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | 573 RadiographyLayer& layer = RegisterLayer(new DicomLayer); |
576 { | 574 layersIndexBySlice_[slice] = layer.GetIndex(); |
577 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&> | 575 |
578 (message.GetPayload()).GetValue(); | 576 slice->RegisterObserverCallback(new Callable<RadiographyScene, IVolumeSlicer::TagsReadyMessage> |
579 | 577 (*this, &RadiographyScene::OnTagsReady)); |
580 LOG(INFO) << "JSON received: " << message.GetUri().c_str() | 578 slice->RegisterObserverCallback(new Callable<RadiographyScene, IVolumeSlicer::FrameReadyMessage> |
581 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; | 579 (*this, &RadiographyScene::OnImageReady)); |
582 | 580 |
583 Layers::iterator layer = layers_.find(index); | 581 // TODO: register failures |
582 | |
583 return layer; | |
584 } | |
585 | |
586 void RadiographyScene::OnTagsReady(const IVolumeSlicer::TagsReadyMessage &message) | |
587 { | |
588 size_t layerIndex = layersIndexBySlice_[&(message.GetOrigin())]; | |
589 Layers::iterator layer = layers_.find(layerIndex); | |
590 | |
584 if (layer != layers_.end()) | 591 if (layer != layers_.end()) |
585 { | 592 { |
586 assert(layer->second != NULL); | 593 assert(layer->second != NULL); |
587 | 594 |
588 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize()); | 595 const OrthancPlugins::FullOrthancDataset& dicom = message.GetDicomTags(); |
589 dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom); | 596 dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom); |
590 | 597 |
591 float c, w; | 598 float c, w; |
592 if (!hasWindowing_ && | 599 if (!hasWindowing_ && |
593 layer->second->GetDefaultWindowing(c, w)) | 600 layer->second->GetDefaultWindowing(c, w)) |
596 windowingCenter_ = c; | 603 windowingCenter_ = c; |
597 windowingWidth_ = w; | 604 windowingWidth_ = w; |
598 } | 605 } |
599 | 606 |
600 EmitMessage(GeometryChangedMessage(*this)); | 607 EmitMessage(GeometryChangedMessage(*this)); |
601 } | 608 |
602 } | 609 CoordinateSystem3D dummy; |
603 | 610 message.GetOrigin().ScheduleLayerCreation(dummy); |
611 } | |
612 | |
613 } | |
614 | |
615 void RadiographyScene::OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | |
616 { | |
617 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&> | |
618 (message.GetPayload()).GetValue(); | |
619 | |
620 LOG(INFO) << "JSON received: " << message.GetUri().c_str() | |
621 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; | |
622 | |
623 Layers::iterator layer = layers_.find(index); | |
624 if (layer != layers_.end()) | |
625 { | |
626 assert(layer->second != NULL); | |
627 | |
628 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize()); | |
629 dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom); | |
630 | |
631 float c, w; | |
632 if (!hasWindowing_ && | |
633 layer->second->GetDefaultWindowing(c, w)) | |
634 { | |
635 hasWindowing_ = true; | |
636 windowingCenter_ = c; | |
637 windowingWidth_ = w; | |
638 } | |
639 | |
640 EmitMessage(GeometryChangedMessage(*this)); | |
641 } | |
642 } | |
643 | |
644 | |
645 void RadiographyScene::OnImageReady(const IVolumeSlicer::FrameReadyMessage &message) | |
646 { | |
647 size_t layerIndex = layersIndexBySlice_[&(message.GetOrigin())]; | |
648 Layers::iterator layer = layers_.find(layerIndex); | |
649 | |
650 if (layer != layers_.end()) | |
651 { | |
652 assert(layer->second != NULL); | |
653 | |
654 dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(message.GetImage()); | |
655 | |
656 EmitMessage(ContentChangedMessage(*this)); | |
657 } | |
658 } | |
604 | 659 |
605 void RadiographyScene::OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) | 660 void RadiographyScene::OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) |
606 { | 661 { |
607 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); | 662 size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); |
608 | 663 |
609 LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str() | 664 LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str() |
610 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; | 665 << " (" << message.GetAnswerSize() << " bytes) for layer " << index; |
611 | 666 |
612 Layers::iterator layer = layers_.find(index); | 667 Layers::iterator layer = layers_.find(index); |
613 if (layer != layers_.end()) | 668 if (layer != layers_.end()) |
614 { | 669 { |
615 assert(layer->second != NULL); | 670 assert(layer->second != NULL); |
616 | 671 |
617 std::string content; | 672 std::string content; |
618 if (message.GetAnswerSize() > 0) | 673 if (message.GetAnswerSize() > 0) |
619 { | 674 { |
620 content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()); | 675 content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()); |
621 } | 676 } |
622 | 677 |
623 std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); | 678 boost::shared_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); |
624 reader->ReadFromMemory(content); | 679 reader->ReadFromMemory(content); |
625 dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader.release()); | 680 dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader); |
626 | 681 |
627 EmitMessage(ContentChangedMessage(*this)); | 682 EmitMessage(ContentChangedMessage(*this)); |
628 } | 683 } |
629 } | 684 } |
630 | 685 |
640 extent.Union(it->second->GetExtent()); | 695 extent.Union(it->second->GetExtent()); |
641 } | 696 } |
642 | 697 |
643 return extent; | 698 return extent; |
644 } | 699 } |
645 | 700 |
646 | 701 |
647 void RadiographyScene::Render(Orthanc::ImageAccessor& buffer, | 702 void RadiographyScene::Render(Orthanc::ImageAccessor& buffer, |
648 const AffineTransform2D& viewTransform, | 703 const AffineTransform2D& viewTransform, |
649 ImageInterpolation interpolation) const | 704 ImageInterpolation interpolation) const |
650 { | 705 { |
683 } | 738 } |
684 | 739 |
685 return false; | 740 return false; |
686 } | 741 } |
687 | 742 |
688 | 743 |
689 void RadiographyScene::DrawBorder(CairoContext& context, | 744 void RadiographyScene::DrawBorder(CairoContext& context, |
690 unsigned int layer, | 745 unsigned int layer, |
691 double zoom) | 746 double zoom) |
692 { | 747 { |
693 Layers::const_iterator found = layers_.find(layer); | 748 Layers::const_iterator found = layers_.find(layer); |
694 | 749 |
695 if (found != layers_.end()) | 750 if (found != layers_.end()) |
696 { | 751 { |
697 context.SetSourceColor(255, 0, 0); | 752 context.SetSourceColor(255, 0, 0); |
698 found->second->DrawBorders(context, zoom); | 753 found->second->DrawBorders(context, zoom); |
699 } | 754 } |
702 | 757 |
703 void RadiographyScene::GetRange(float& minValue, | 758 void RadiographyScene::GetRange(float& minValue, |
704 float& maxValue) const | 759 float& maxValue) const |
705 { | 760 { |
706 bool first = true; | 761 bool first = true; |
707 | 762 |
708 for (Layers::const_iterator it = layers_.begin(); | 763 for (Layers::const_iterator it = layers_.begin(); |
709 it != layers_.end(); it++) | 764 it != layers_.end(); it++) |
710 { | 765 { |
711 assert(it->second != NULL); | 766 assert(it->second != NULL); |
712 | 767 |
748 if (pixelSpacingX <= 0 || | 803 if (pixelSpacingX <= 0 || |
749 pixelSpacingY <= 0) | 804 pixelSpacingY <= 0) |
750 { | 805 { |
751 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 806 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
752 } | 807 } |
753 | 808 |
754 LOG(INFO) << "Exporting DICOM"; | 809 LOG(INFO) << "Exporting DICOM"; |
755 | 810 |
756 Extent2D extent = GetSceneExtent(); | 811 Extent2D extent = GetSceneExtent(); |
757 | 812 |
758 int w = std::ceil(extent.GetWidth() / pixelSpacingX); | 813 int w = std::ceil(extent.GetWidth() / pixelSpacingX); |
766 Orthanc::Image layers(Orthanc::PixelFormat_Float32, | 821 Orthanc::Image layers(Orthanc::PixelFormat_Float32, |
767 static_cast<unsigned int>(w), | 822 static_cast<unsigned int>(w), |
768 static_cast<unsigned int>(h), false); | 823 static_cast<unsigned int>(h), false); |
769 | 824 |
770 AffineTransform2D view = AffineTransform2D::Combine( | 825 AffineTransform2D view = AffineTransform2D::Combine( |
771 AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), | 826 AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), |
772 AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1())); | 827 AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1())); |
773 | 828 |
774 Render(layers, view, interpolation); | 829 Render(layers, view, interpolation); |
775 | 830 |
776 Orthanc::Image rendered(Orthanc::PixelFormat_Grayscale16, | 831 Orthanc::Image rendered(Orthanc::PixelFormat_Grayscale16, |
777 layers.GetWidth(), layers.GetHeight(), false); | 832 layers.GetWidth(), layers.GetHeight(), false); |
778 Orthanc::ImageProcessing::Convert(rendered, layers); | 833 Orthanc::ImageProcessing::Convert(rendered, layers); |
799 std::set<Orthanc::DicomTag> tags; | 854 std::set<Orthanc::DicomTag> tags; |
800 dicom.GetTags(tags); | 855 dicom.GetTags(tags); |
801 | 856 |
802 Json::Value json = Json::objectValue; | 857 Json::Value json = Json::objectValue; |
803 json["Tags"] = Json::objectValue; | 858 json["Tags"] = Json::objectValue; |
804 | 859 |
805 for (std::set<Orthanc::DicomTag>::const_iterator | 860 for (std::set<Orthanc::DicomTag>::const_iterator |
806 tag = tags.begin(); tag != tags.end(); ++tag) | 861 tag = tags.begin(); tag != tags.end(); ++tag) |
807 { | 862 { |
808 const Orthanc::DicomValue& value = dicom.GetValue(*tag); | 863 const Orthanc::DicomValue& value = dicom.GetValue(*tag); |
809 if (!value.IsNull() && | 864 if (!value.IsNull() && |
810 !value.IsBinary()) | 865 !value.IsBinary()) |
811 { | 866 { |
812 json["Tags"][tag->Format()] = value.GetContent(); | 867 json["Tags"][tag->Format()] = value.GetContent(); |
813 } | 868 } |
814 } | 869 } |
815 | 870 |
816 json["Tags"][Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION.Format()] = | 871 json["Tags"][Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION.Format()] = |
817 (invert ? "MONOCHROME1" : "MONOCHROME2"); | 872 (invert ? "MONOCHROME1" : "MONOCHROME2"); |
818 | 873 |
819 // WARNING: The order of PixelSpacing is Y/X. We use "%0.8f" to | 874 // WARNING: The order of PixelSpacing is Y/X. We use "%0.8f" to |
820 // avoid floating-point numbers to grow over 16 characters, | 875 // avoid floating-point numbers to grow over 16 characters, |
821 // which would be invalid according to DICOM standard | 876 // which would be invalid according to DICOM standard |
822 // ("dciodvfy" would complain). | 877 // ("dciodvfy" would complain). |
823 char buf[32]; | 878 char buf[32]; |
824 sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); | 879 sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); |
825 | 880 |
826 json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf; | 881 json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf; |
827 | 882 |
828 float center, width; | 883 float center, width; |
829 if (GetWindowing(center, width)) | 884 if (GetWindowing(center, width)) |
830 { | 885 { |
831 json["Tags"][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()] = | 886 json["Tags"][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()] = |
832 boost::lexical_cast<std::string>(boost::math::iround(center)); | 887 boost::lexical_cast<std::string>(boost::math::iround(center)); |
833 | 888 |
834 json["Tags"][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()] = | 889 json["Tags"][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()] = |
835 boost::lexical_cast<std::string>(boost::math::iround(width)); | 890 boost::lexical_cast<std::string>(boost::math::iround(width)); |
836 } | 891 } |
837 | 892 |
838 // This is Data URI scheme: https://en.wikipedia.org/wiki/Data_URI_scheme | 893 // This is Data URI scheme: https://en.wikipedia.org/wiki/Data_URI_scheme |
839 json["Content"] = ("data:" + | 894 json["Content"] = ("data:" + |
840 std::string(usePam ? Orthanc::MIME_PAM : Orthanc::MIME_PNG) + | 895 std::string(usePam ? Orthanc::MIME_PAM : Orthanc::MIME_PNG) + |
841 ";base64," + base64); | 896 ";base64," + base64); |
842 | 897 |
843 orthanc.PostJsonAsyncExpectJson( | 898 orthanc.PostJsonAsyncExpectJson( |
844 "/tools/create-dicom", json, | 899 "/tools/create-dicom", json, |
845 new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage> | 900 new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage> |
846 (*this, &RadiographyScene::OnDicomExported), | 901 (*this, &RadiographyScene::OnDicomExported), |
847 NULL, NULL); | 902 NULL, NULL); |
848 } | 903 } |
849 | 904 |
850 | 905 |
851 void RadiographyScene::OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message) | 906 void RadiographyScene::OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message) |
852 { | 907 { |
859 { | 914 { |
860 LOG(INFO) << "DICOMweb WADO-RS received: " << message.GetAnswerSize() << " bytes"; | 915 LOG(INFO) << "DICOMweb WADO-RS received: " << message.GetAnswerSize() << " bytes"; |
861 | 916 |
862 const IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders(); | 917 const IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders(); |
863 for (IWebService::HttpHeaders::const_iterator | 918 for (IWebService::HttpHeaders::const_iterator |
864 it = h.begin(); it != h.end(); ++it) | 919 it = h.begin(); it != h.end(); ++it) |
865 { | 920 { |
866 printf("[%s] = [%s]\n", it->first.c_str(), it->second.c_str()); | 921 printf("[%s] = [%s]\n", it->first.c_str(), it->second.c_str()); |
867 } | 922 } |
868 } | 923 } |
869 | 924 |