# HG changeset patch # User Sebastien Jodogne # Date 1540052765 -7200 # Node ID f5d5814a41a0c6132392c9cf0bb99c204c13925f # Parent 5a7915b23138f772794676f49fb93da8f0d742f9 rendering BitmapStack diff -r 5a7915b23138 -r f5d5814a41a0 Applications/Samples/SingleFrameEditorApplication.h --- a/Applications/Samples/SingleFrameEditorApplication.h Fri Oct 19 14:44:12 2018 +0200 +++ b/Applications/Samples/SingleFrameEditorApplication.h Sat Oct 20 18:26:05 2018 +0200 @@ -35,6 +35,9 @@ #include #include + +#include + namespace OrthancStone { class BitmapStack : @@ -85,11 +88,11 @@ double y) const { Vector p; - LinearAlgebra::AssignVector(p, x, y, 0); + LinearAlgebra::AssignVector(p, x, y, 1); Vector q = LinearAlgebra::Product(transform_, p); - if (!LinearAlgebra::IsCloseToZero(q[2])) + if (!LinearAlgebra::IsNear(q[2], 1.0)) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } @@ -184,6 +187,25 @@ transform_(1, 1) = pixelSpacing[1]; } + +#if 0 + double a = 10.0 / 180.0 * boost::math::constants::pi(); + Matrix m; + const double v[] = { cos(a), -sin(a), 0, + sin(a), cos(a), 0, + 0, 0, 1 }; + LinearAlgebra::FillMatrix(m, 3, 3, v); + transform_ = LinearAlgebra::Product(m, transform_); + +#else + static unsigned int c = 0; + if (c == 0) + { + transform_(0, 2) = 400; + c ++; + } +#endif + OrthancPlugins::DicomDatasetReader reader(dataset); if (!reader.GetUnsignedIntegerValue(width_, ConvertTag(Orthanc::DICOM_TAG_COLUMNS)) || @@ -244,7 +266,8 @@ { if (converted_.get() != NULL) { - ApplyProjectiveTransform(buffer, *converted_, transform_, ImageInterpolation_Nearest); // TODO + Matrix m = LinearAlgebra::Product(view.GetMatrix(), transform_); + ApplyProjectiveTransform(buffer, *converted_, m, ImageInterpolation_Bilinear, false); } } }; @@ -402,7 +425,7 @@ Extent2D GetSceneExtent() const { Extent2D extent; - + for (Bitmaps::const_iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) { @@ -410,10 +433,6 @@ extent.Union(it->second->GetExtent()); } - printf("(%.02f,%.02f) (%.02f,%.02f) \n", - extent.GetX1(), extent.GetY1(), - extent.GetX2(), extent.GetY2()); - return extent; } @@ -451,10 +470,41 @@ virtual bool RenderScene(CairoContext& context, const ViewportGeometry& view) { - Orthanc::Image buffer(Orthanc::PixelFormat_Float32, context.GetWidth(), context.GetHeight(), false); - stack_.Render(buffer, view); + // "Render()" has been replaced + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + public: + BitmapStackWidget(MessageBroker& broker, + BitmapStack& stack, + const std::string& name) : + WorldSceneWidget(name), + IObservable(broker), + IObserver(broker), + stack_(stack) + { + stack.RegisterObserverCallback(new Callable(*this, &BitmapStackWidget::OnGeometryChanged)); + stack.RegisterObserverCallback(new Callable(*this, &BitmapStackWidget::OnContentChanged)); + } - // As in GrayscaleFrameRenderer + void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message) + { + printf("Geometry has changed\n"); + FitContent(); + } + + void OnContentChanged(const BitmapStack::ContentChangedMessage& message) + { + printf("Content has changed\n"); + NotifyContentChanged(); + } + + virtual bool Render(Orthanc::ImageAccessor& target) + { + Orthanc::Image buffer(Orthanc::PixelFormat_Float32, target.GetWidth(), target.GetHeight(), false); + stack_.Render(buffer, GetView()); + + // As in GrayscaleFrameRenderer => TODO MERGE float windowCenter, windowWidth; stack_.GetWindowing(windowCenter, windowWidth); @@ -462,13 +512,8 @@ float x0 = windowCenter - windowWidth / 2.0f; float x1 = windowCenter + windowWidth / 2.0f; - CairoSurface cairo(context.GetWidth(), context.GetHeight()); - - Orthanc::ImageAccessor target; - cairo.GetAccessor(target); - - const unsigned int width = cairo.GetWidth(); - const unsigned int height = cairo.GetHeight(); + const unsigned int width = target.GetWidth(); + const unsigned int height = target.GetHeight(); for (unsigned int y = 0; y < height; y++) { @@ -496,7 +541,7 @@ // TODO MONOCHROME1 /*if (invert_) - { + { v = 255 - v; }*/ } @@ -504,68 +549,21 @@ q[3] = 255; q[2] = v; q[1] = v; - q[0] = 128; + q[0] = v; } } - - - cairo_t* cr = context.GetObject(); - - // Clear background - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_paint(cr); - -#if 1 - cairo_save(cr); - cairo_set_source_surface(cr, cairo.GetObject(), 0, 0); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); //TODO - cairo_paint(cr); - cairo_restore(cr); -#else - Extent2D extent = stack_.GetSceneExtent(); - - float color = 0.5; - cairo_set_source_rgb(cr, 0, 1.0f - color, color); - cairo_rectangle(cr, extent.GetX1(), extent.GetY1(), extent.GetX2(), extent.GetY2()); - cairo_fill(cr); -#endif - return true; } - public: - BitmapStackWidget(MessageBroker& broker, - BitmapStack& stack, - const std::string& name) : - WorldSceneWidget(name), - IObservable(broker), - IObserver(broker), - stack_(stack) - { - stack.RegisterObserverCallback(new Callable(*this, &BitmapStackWidget::OnGeometryChanged)); - stack.RegisterObserverCallback(new Callable(*this, &BitmapStackWidget::OnContentChanged)); - } - - void OnGeometryChanged(const BitmapStack::GeometryChangedMessage& message) - { - printf("Geometry has changed\n"); - FitContent(); - } - - void OnContentChanged(const BitmapStack::ContentChangedMessage& message) - { - printf("Content has changed\n"); - NotifyContentChanged(); - } }; namespace Samples { class SingleFrameEditorApplication : - public SampleSingleCanvasApplicationBase, - public IObserver + public SampleSingleCanvasApplicationBase, + public IObserver { enum Tools { @@ -603,14 +601,14 @@ IStatusBar* statusBar) { switch (application_.currentTool_) { - case Tools_Zoom: - printf("ZOOM\n"); + case Tools_Zoom: + printf("ZOOM\n"); case Tools_Crop: - case Tools_Windowing: - case Tools_Pan: - // TODO return the right mouse tracker - return NULL; + case Tools_Windowing: + case Tools_Pan: + // TODO return the right mouse tracker + return NULL; } return NULL; @@ -646,35 +644,35 @@ { switch (keyChar) { - case 's': - widget.FitContent(); - break; - case 'p': - application_.currentTool_ = Tools_Pan; - break; - case 'z': - application_.currentTool_ = Tools_Zoom; - break; - case 'c': - application_.currentTool_ = Tools_Crop; - break; - case 'w': - application_.currentTool_ = Tools_Windowing; - break; - case 'i': - application_.Invert(); - break; - case 'r': - if (modifiers == KeyboardModifiers_None) - application_.Rotate(90); - else - application_.Rotate(-90); - break; - case 'e': - application_.Export(); - break; - default: - break; + case 's': + widget.FitContent(); + break; + case 'p': + application_.currentTool_ = Tools_Pan; + break; + case 'z': + application_.currentTool_ = Tools_Zoom; + break; + case 'c': + application_.currentTool_ = Tools_Crop; + break; + case 'w': + application_.currentTool_ = Tools_Windowing; + break; + case 'i': + application_.Invert(); + break; + case 'r': + if (modifiers == KeyboardModifiers_None) + application_.Rotate(90); + else + application_.Rotate(-90); + break; + case 'e': + application_.Export(); + break; + default: + break; } } }; @@ -699,11 +697,11 @@ { boost::program_options::options_description generic("Sample options"); generic.add_options() - ("instance", boost::program_options::value(), - "Orthanc ID of the instance") - ("frame", boost::program_options::value()->default_value(0), - "Number of the frame, for multi-frame DICOM instances") - ; + ("instance", boost::program_options::value(), + "Orthanc ID of the instance") + ("frame", boost::program_options::value()->default_value(0), + "Number of the frame, for multi-frame DICOM instances") + ; options.add(generic); } @@ -731,7 +729,7 @@ stack_.reset(new BitmapStack(IObserver::broker_, *orthancApiClient_)); stack_->LoadFrame(instance, frame, false); - //stack_->LoadFrame(instance, frame, false); + stack_->LoadFrame("61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", frame, false); mainWidget_ = new BitmapStackWidget(IObserver::broker_, *stack_, "main-widget"); mainWidget_->SetTransmitMouseOver(true); diff -r 5a7915b23138 -r f5d5814a41a0 Framework/Toolbox/ImageGeometry.cpp --- a/Framework/Toolbox/ImageGeometry.cpp Fri Oct 19 14:44:12 2018 +0200 +++ b/Framework/Toolbox/ImageGeometry.cpp Sat Oct 20 18:26:05 2018 +0200 @@ -174,7 +174,8 @@ ImageInterpolation Interpolation> static void ApplyAffineInternal(Orthanc::ImageAccessor& target, const Orthanc::ImageAccessor& source, - const Matrix& a) + const Matrix& a, + bool clear) { assert(target.GetFormat() == Format && source.GetFormat() == Format); @@ -182,13 +183,16 @@ typedef SubpixelReader Reader; typedef typename Reader::PixelType PixelType; - if (Format == Orthanc::PixelFormat_RGB24) + if (clear) { - Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255); - } - else - { - Orthanc::ImageProcessing::Set(target, 0); + if (Format == Orthanc::PixelFormat_RGB24) + { + Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255); + } + else + { + Orthanc::ImageProcessing::Set(target, 0); + } } Matrix inva; @@ -260,7 +264,8 @@ double a21, double a22, double b2, - ImageInterpolation interpolation) + ImageInterpolation interpolation, + bool clear) { if (source.GetFormat() != target.GetFormat()) { @@ -292,12 +297,12 @@ { case ImageInterpolation_Nearest: ApplyAffineInternal(target, source, a); + ImageInterpolation_Nearest>(target, source, a, clear); break; case ImageInterpolation_Bilinear: ApplyAffineInternal(target, source, a); + ImageInterpolation_Bilinear>(target, source, a, clear); break; default: @@ -310,12 +315,12 @@ { case ImageInterpolation_Nearest: ApplyAffineInternal(target, source, a); + ImageInterpolation_Nearest>(target, source, a, clear); break; case ImageInterpolation_Bilinear: ApplyAffineInternal(target, source, a); + ImageInterpolation_Bilinear>(target, source, a, clear); break; default: @@ -328,12 +333,12 @@ { case ImageInterpolation_Nearest: ApplyAffineInternal(target, source, a); + ImageInterpolation_Nearest>(target, source, a, clear); break; case ImageInterpolation_Bilinear: ApplyAffineInternal(target, source, a); + ImageInterpolation_Bilinear>(target, source, a, clear); break; default: @@ -346,12 +351,12 @@ { case ImageInterpolation_Nearest: ApplyAffineInternal(target, source, a); + ImageInterpolation_Nearest>(target, source, a, clear); break; case ImageInterpolation_Bilinear: ApplyAffineInternal(target, source, a); + ImageInterpolation_Bilinear>(target, source, a, clear); break; default: @@ -364,7 +369,7 @@ { case ImageInterpolation_Nearest: ApplyAffineInternal(target, source, a); + ImageInterpolation_Nearest>(target, source, a, clear); break; default: @@ -447,7 +452,8 @@ void ApplyProjectiveTransform(Orthanc::ImageAccessor& target, const Orthanc::ImageAccessor& source, const Matrix& a, - ImageInterpolation interpolation) + ImageInterpolation interpolation, + bool clear) { if (source.GetFormat() != target.GetFormat()) { @@ -481,18 +487,21 @@ ApplyAffineTransform(target, source, a(0, 0) / w, a(0, 1) / w, a(0, 2) / w, a(1, 0) / w, a(1, 1) / w, a(1, 2) / w, - interpolation); + interpolation, clear); return; } } - if (target.GetFormat() == Orthanc::PixelFormat_RGB24) + if (clear) { - Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255); - } - else - { - Orthanc::ImageProcessing::Set(target, 0); + if (target.GetFormat() == Orthanc::PixelFormat_RGB24) + { + Orthanc::ImageProcessing::Set(target, 0, 0, 0, 255); + } + else + { + Orthanc::ImageProcessing::Set(target, 0); + } } Matrix inva; diff -r 5a7915b23138 -r f5d5814a41a0 Framework/Toolbox/ImageGeometry.h --- a/Framework/Toolbox/ImageGeometry.h Fri Oct 19 14:44:12 2018 +0200 +++ b/Framework/Toolbox/ImageGeometry.h Sat Oct 20 18:26:05 2018 +0200 @@ -50,10 +50,12 @@ double a21, double a22, double b2, - ImageInterpolation interpolation); + ImageInterpolation interpolation, + bool clear); void ApplyProjectiveTransform(Orthanc::ImageAccessor& target, const Orthanc::ImageAccessor& source, const Matrix& a, - ImageInterpolation interpolation); + ImageInterpolation interpolation, + bool clear); } diff -r 5a7915b23138 -r f5d5814a41a0 Framework/Toolbox/ShearWarpProjectiveTransform.cpp --- a/Framework/Toolbox/ShearWarpProjectiveTransform.cpp Fri Oct 19 14:44:12 2018 +0200 +++ b/Framework/Toolbox/ShearWarpProjectiveTransform.cpp Sat Oct 20 18:26:05 2018 +0200 @@ -476,7 +476,7 @@ ApplyAffineTransform(*intermediate, reader.GetAccessor(), a11, 0, b1, 0, a22, b2, - shearInterpolation); + shearInterpolation, true); } @@ -582,7 +582,7 @@ } // (5.b) Apply the projective transform to the image - ApplyProjectiveTransform(target, *intermediate, warp, warpInterpolation); + ApplyProjectiveTransform(target, *intermediate, warp, warpInterpolation, true); } diff -r 5a7915b23138 -r f5d5814a41a0 Framework/Toolbox/ViewportGeometry.cpp --- a/Framework/Toolbox/ViewportGeometry.cpp Fri Oct 19 14:44:12 2018 +0200 +++ b/Framework/Toolbox/ViewportGeometry.cpp Sat Oct 20 18:26:05 2018 +0200 @@ -179,4 +179,22 @@ zoom_ = zoom; ComputeTransform(); } + + + Matrix ViewportGeometry::GetMatrix() const + { + Matrix m(3, 3); + + m(0, 0) = transform_.xx; + m(0, 1) = transform_.xy; + m(0, 2) = transform_.x0; + m(1, 0) = transform_.yx; + m(1, 1) = transform_.yy; + m(1, 2) = transform_.y0; + m(2, 0) = 0; + m(2, 1) = 0; + m(2, 2) = 1; + + return m; + } } diff -r 5a7915b23138 -r f5d5814a41a0 Framework/Toolbox/ViewportGeometry.h --- a/Framework/Toolbox/ViewportGeometry.h Fri Oct 19 14:44:12 2018 +0200 +++ b/Framework/Toolbox/ViewportGeometry.h Sat Oct 20 18:26:05 2018 +0200 @@ -22,7 +22,8 @@ #pragma once #include "../Viewport/CairoContext.h" -#include "../Toolbox/Extent2D.h" +#include "Extent2D.h" +#include "LinearAlgebra.h" namespace OrthancStone { @@ -99,5 +100,7 @@ double y); void SetZoom(double zoom); + + Matrix GetMatrix() const; }; }