Mercurial > hg > orthanc-stone
diff 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 |
line wrap: on
line diff
--- a/Framework/Radiography/RadiographyScene.cpp Mon Nov 19 12:45:37 2018 +0100 +++ b/Framework/Radiography/RadiographyScene.cpp Tue Nov 20 16:35:29 2018 +0100 @@ -55,7 +55,7 @@ } } - + RadiographyScene::LayerAccessor::LayerAccessor(RadiographyScene& scene, double x, double y) : @@ -65,7 +65,7 @@ if (scene.LookupLayer(index_, x, y)) { Layers::iterator layer = scene.layers_.find(index_); - + if (layer == scene.layers_.end()) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); @@ -119,7 +119,7 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - } + } @@ -145,12 +145,12 @@ useWindowing_ = false; foreground_ = foreground; } - - + + void SetAlpha(Orthanc::ImageAccessor* image) { std::auto_ptr<Orthanc::ImageAccessor> raii(image); - + if (image == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); @@ -170,7 +170,7 @@ const std::string& utf8) { SetAlpha(font.RenderAlpha(utf8)); - } + } virtual bool GetDefaultWindowing(float& center, @@ -178,7 +178,7 @@ { return false; } - + virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, @@ -188,7 +188,7 @@ { return; } - + if (buffer.GetFormat() != Orthanc::PixelFormat_Float32) { throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); @@ -198,12 +198,12 @@ GetCrop(cropX, cropY, cropWidth, cropHeight); const AffineTransform2D t = AffineTransform2D::Combine( - viewTransform, GetTransform(), - AffineTransform2D::CreateOffset(cropX, cropY)); + viewTransform, GetTransform(), + AffineTransform2D::CreateOffset(cropX, cropY)); Orthanc::ImageAccessor cropped; alpha_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); - + Orthanc::Image tmp(Orthanc::PixelFormat_Grayscale8, buffer.GetWidth(), buffer.GetHeight(), false); t.Apply(tmp, cropped, interpolation, true /* clear */); @@ -213,7 +213,7 @@ const unsigned int height = buffer.GetHeight(); float value = foreground_; - + if (useWindowing_) { float center, width; @@ -222,7 +222,7 @@ value = center + width / 2.0f; } } - + for (unsigned int y = 0; y < height; y++) { float *q = reinterpret_cast<float*>(buffer.GetRow(y)); @@ -231,13 +231,13 @@ for (unsigned int x = 0; x < width; x++, p++, q++) { float a = static_cast<float>(*p) / 255.0f; - + *q = (a * value + (1.0f - a) * (*q)); } - } + } } - + virtual bool GetRange(float& minValue, float& maxValue) const { @@ -264,13 +264,13 @@ } } }; - - + + class RadiographyScene::DicomLayer : public RadiographyLayer { private: - std::auto_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData + boost::shared_ptr<Orthanc::ImageAccessor> source_; // Content of PixelData std::auto_ptr<DicomFrameConverter> converter_; std::auto_ptr<Orthanc::ImageAccessor> converted_; // Float32 @@ -278,7 +278,7 @@ { return OrthancPlugins::DicomTag(tag.GetGroup(), tag.GetElement()); } - + void ApplyConverter() { @@ -288,7 +288,7 @@ converted_.reset(converter_->ConvertFrame(*source_)); } } - + public: void SetDicomTags(const OrthancPlugins::FullOrthancDataset& dataset) { @@ -298,7 +298,7 @@ std::string tmp; Vector pixelSpacing; - + if (dataset.GetStringValue(tmp, ConvertTag(Orthanc::DICOM_TAG_PIXEL_SPACING)) && LinearAlgebra::ParseVector(pixelSpacing, tmp) && pixelSpacing.size() == 2) @@ -322,23 +322,21 @@ } } - - void SetSourceImage(Orthanc::ImageAccessor* image) // Takes ownership + + void SetSourceImage(boost::shared_ptr<Orthanc::ImageAccessor> image) { - std::auto_ptr<Orthanc::ImageAccessor> raii(image); - - if (image == NULL) + if (image.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); } SetSize(image->GetWidth(), image->GetHeight()); - - source_ = raii; + + source_ = image; ApplyConverter(); } - + virtual void Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const @@ -354,8 +352,8 @@ GetCrop(cropX, cropY, cropWidth, cropHeight); AffineTransform2D t = AffineTransform2D::Combine( - viewTransform, GetTransform(), - AffineTransform2D::CreateOffset(cropX, cropY)); + viewTransform, GetTransform(), + AffineTransform2D::CreateOffset(cropX, cropY)); Orthanc::ImageAccessor cropped; converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); @@ -411,7 +409,7 @@ } std::auto_ptr<RadiographyLayer> raii(layer); - + size_t index = countLayers_++; raii->SetIndex(index); layers_[index] = raii.release(); @@ -421,7 +419,7 @@ return *layer; } - + RadiographyScene::RadiographyScene(MessageBroker& broker) : IObserver(broker), @@ -489,7 +487,7 @@ return RegisterLayer(alpha.release()); } - + RadiographyLayer& RadiographyScene::LoadTestBlock(unsigned int width, unsigned int height) { @@ -520,7 +518,7 @@ return RegisterLayer(alpha.release()); } - + RadiographyLayer& RadiographyScene::LoadDicomFrame(OrthancApiClient& orthanc, const std::string& instance, unsigned int frame, @@ -531,12 +529,12 @@ { IWebService::HttpHeaders headers; std::string uri = "/instances/" + instance + "/tags"; - + orthanc.GetBinaryAsync( - uri, headers, - new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> - (*this, &RadiographyScene::OnTagsReceived), NULL, - new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); + uri, headers, + new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> + (*this, &RadiographyScene::OnTagsReceived), NULL, + new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); } { @@ -547,15 +545,15 @@ { headers["Accept-Encoding"] = "gzip"; } - + std::string uri = ("/instances/" + instance + "/frames/" + boost::lexical_cast<std::string>(frame) + "/image-uint16"); - + orthanc.GetBinaryAsync( - uri, headers, - new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> - (*this, &RadiographyScene::OnFrameReceived), NULL, - new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); + uri, headers, + new Callable<RadiographyScene, OrthancApiClient::BinaryResponseReadyMessage> + (*this, &RadiographyScene::OnFrameReceived), NULL, + new Orthanc::SingleValueObject<size_t>(layer.GetIndex())); } return layer; @@ -566,25 +564,67 @@ { RadiographyLayer& layer = RegisterLayer(new DicomLayer); - + + return layer; + } + + RadiographyLayer& RadiographyScene::SetFrame(IVolumeSlicer* slice) + { + RadiographyLayer& layer = RegisterLayer(new DicomLayer); + layersIndexBySlice_[slice] = layer.GetIndex(); + + slice->RegisterObserverCallback(new Callable<RadiographyScene, IVolumeSlicer::TagsReadyMessage> + (*this, &RadiographyScene::OnTagsReady)); + slice->RegisterObserverCallback(new Callable<RadiographyScene, IVolumeSlicer::FrameReadyMessage> + (*this, &RadiographyScene::OnImageReady)); + + // TODO: register failures + return layer; } + void RadiographyScene::OnTagsReady(const IVolumeSlicer::TagsReadyMessage &message) + { + size_t layerIndex = layersIndexBySlice_[&(message.GetOrigin())]; + Layers::iterator layer = layers_.find(layerIndex); - + if (layer != layers_.end()) + { + assert(layer->second != NULL); + + const OrthancPlugins::FullOrthancDataset& dicom = message.GetDicomTags(); + dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom); + + float c, w; + if (!hasWindowing_ && + layer->second->GetDefaultWindowing(c, w)) + { + hasWindowing_ = true; + windowingCenter_ = c; + windowingWidth_ = w; + } + + EmitMessage(GeometryChangedMessage(*this)); + + CoordinateSystem3D dummy; + message.GetOrigin().ScheduleLayerCreation(dummy); + } + + } + void RadiographyScene::OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) { size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&> - (message.GetPayload()).GetValue(); + (message.GetPayload()).GetValue(); LOG(INFO) << "JSON received: " << message.GetUri().c_str() << " (" << message.GetAnswerSize() << " bytes) for layer " << index; - + Layers::iterator layer = layers_.find(index); if (layer != layers_.end()) { assert(layer->second != NULL); - + OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize()); dynamic_cast<DicomLayer*>(layer->second)->SetDicomTags(dicom); @@ -600,15 +640,30 @@ EmitMessage(GeometryChangedMessage(*this)); } } - + + + void RadiographyScene::OnImageReady(const IVolumeSlicer::FrameReadyMessage &message) + { + size_t layerIndex = layersIndexBySlice_[&(message.GetOrigin())]; + Layers::iterator layer = layers_.find(layerIndex); + + if (layer != layers_.end()) + { + assert(layer->second != NULL); + + dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(message.GetImage()); + + EmitMessage(ContentChangedMessage(*this)); + } + } void RadiographyScene::OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message) { size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue(); - + LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str() << " (" << message.GetAnswerSize() << " bytes) for layer " << index; - + Layers::iterator layer = layers_.find(index); if (layer != layers_.end()) { @@ -619,10 +674,10 @@ { content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()); } - - std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); + + boost::shared_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader); reader->ReadFromMemory(content); - dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader.release()); + dynamic_cast<DicomLayer*>(layer->second)->SetSourceImage(reader); EmitMessage(ContentChangedMessage(*this)); } @@ -642,7 +697,7 @@ return extent; } - + void RadiographyScene::Render(Orthanc::ImageAccessor& buffer, const AffineTransform2D& viewTransform, @@ -685,13 +740,13 @@ return false; } - + void RadiographyScene::DrawBorder(CairoContext& context, unsigned int layer, double zoom) { Layers::const_iterator found = layers_.find(layer); - + if (found != layers_.end()) { context.SetSourceColor(255, 0, 0); @@ -704,7 +759,7 @@ float& maxValue) const { bool first = true; - + for (Layers::const_iterator it = layers_.begin(); it != layers_.end(); it++) { @@ -750,7 +805,7 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - + LOG(INFO) << "Exporting DICOM"; Extent2D extent = GetSceneExtent(); @@ -768,9 +823,9 @@ static_cast<unsigned int>(h), false); AffineTransform2D view = AffineTransform2D::Combine( - AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), - AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1())); - + AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), + AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1())); + Render(layers, view, interpolation); Orthanc::Image rendered(Orthanc::PixelFormat_Grayscale16, @@ -801,9 +856,9 @@ Json::Value json = Json::objectValue; json["Tags"] = Json::objectValue; - + for (std::set<Orthanc::DicomTag>::const_iterator - tag = tags.begin(); tag != tags.end(); ++tag) + tag = tags.begin(); tag != tags.end(); ++tag) { const Orthanc::DicomValue& value = dicom.GetValue(*tag); if (!value.IsNull() && @@ -814,7 +869,7 @@ } json["Tags"][Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION.Format()] = - (invert ? "MONOCHROME1" : "MONOCHROME2"); + (invert ? "MONOCHROME1" : "MONOCHROME2"); // WARNING: The order of PixelSpacing is Y/X. We use "%0.8f" to // avoid floating-point numbers to grow over 16 characters, @@ -822,17 +877,17 @@ // ("dciodvfy" would complain). char buf[32]; sprintf(buf, "%0.8f\\%0.8f", pixelSpacingY, pixelSpacingX); - + json["Tags"][Orthanc::DICOM_TAG_PIXEL_SPACING.Format()] = buf; float center, width; if (GetWindowing(center, width)) { json["Tags"][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()] = - boost::lexical_cast<std::string>(boost::math::iround(center)); + boost::lexical_cast<std::string>(boost::math::iround(center)); json["Tags"][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()] = - boost::lexical_cast<std::string>(boost::math::iround(width)); + boost::lexical_cast<std::string>(boost::math::iround(width)); } // This is Data URI scheme: https://en.wikipedia.org/wiki/Data_URI_scheme @@ -841,10 +896,10 @@ ";base64," + base64); orthanc.PostJsonAsyncExpectJson( - "/tools/create-dicom", json, - new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage> - (*this, &RadiographyScene::OnDicomExported), - NULL, NULL); + "/tools/create-dicom", json, + new Callable<RadiographyScene, OrthancApiClient::JsonResponseReadyMessage> + (*this, &RadiographyScene::OnDicomExported), + NULL, NULL); } @@ -861,7 +916,7 @@ const IWebService::HttpHeaders& h = message.GetAnswerHttpHeaders(); for (IWebService::HttpHeaders::const_iterator - it = h.begin(); it != h.end(); ++it) + it = h.begin(); it != h.end(); ++it) { printf("[%s] = [%s]\n", it->first.c_str(), it->second.c_str()); }