comparison Framework/Radiography/RadiographyWidget.cpp @ 432:4eb96c6b4e96 am-vsol-upgrade

improved handling of MONOCHROME1, background and invertion
author am@osimis.io
date Mon, 03 Dec 2018 13:53:29 +0100
parents 751fb354149e
children a750f11892ec
comparison
equal deleted inserted replaced
431:26b90b110719 432:4eb96c6b4e96
19 **/ 19 **/
20 20
21 21
22 #include "RadiographyWidget.h" 22 #include "RadiographyWidget.h"
23 23
24 #include <Core/OrthancException.h>
24 #include <Core/Images/Image.h> 25 #include <Core/Images/Image.h>
26 #include <Core/Images/ImageProcessing.h>
25 27
26 28
27 namespace OrthancStone 29 namespace OrthancStone
28 { 30 {
31
32 bool RadiographyWidget::IsInvertedInternal() const
33 {
34 return (scene_->GetPreferredPhotomotricDisplayMode() == PhotometricDisplayMode_Monochrome1) ^ invert_; // MONOCHROME1 images must be inverted and the user can invert the image too -> XOR the two
35 }
36
37 void RadiographyWidget::RenderBackground(Orthanc::ImageAccessor& image, float minValue, float maxValue)
38 {
39 // wipe background before rendering
40 float backgroundValue = minValue;
41
42 switch (scene_->GetPreferredPhotomotricDisplayMode())
43 {
44 case PhotometricDisplayMode_Monochrome1:
45 case PhotometricDisplayMode_Default:
46 if (IsInvertedInternal())
47 backgroundValue = maxValue;
48 else
49 backgroundValue = minValue;
50 break;
51 case PhotometricDisplayMode_Monochrome2:
52 if (IsInvertedInternal())
53 backgroundValue = minValue;
54 else
55 backgroundValue = maxValue;
56 break;
57 default:
58 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
59 }
60
61 Orthanc::ImageProcessing::Set(image, backgroundValue);
62 }
63
29 bool RadiographyWidget::RenderInternal(unsigned int width, 64 bool RadiographyWidget::RenderInternal(unsigned int width,
30 unsigned int height, 65 unsigned int height,
31 ImageInterpolation interpolation) 66 ImageInterpolation interpolation)
32 { 67 {
33 float windowCenter, windowWidth; 68 float windowCenter, windowWidth;
34 scene_->GetWindowingWithDefault(windowCenter, windowWidth); 69 scene_->GetWindowingWithDefault(windowCenter, windowWidth);
35 70
36 float x0 = windowCenter - windowWidth / 2.0f; 71 float x0 = windowCenter - windowWidth / 2.0f;
37 float x1 = windowCenter + windowWidth / 2.0f; 72 float x1 = windowCenter + windowWidth / 2.0f;
38 73
39 if (windowWidth <= 0.001f) // Avoid division by zero at (*) 74 if (windowWidth <= 0.001f) // Avoid division by zero at (*)
40 { 75 {
54 cairoBuffer_->GetHeight() != height) 89 cairoBuffer_->GetHeight() != height)
55 { 90 {
56 cairoBuffer_.reset(new CairoSurface(width, height)); 91 cairoBuffer_.reset(new CairoSurface(width, height));
57 } 92 }
58 93
94 RenderBackground(*floatBuffer_, x0, x1);
95
59 scene_->Render(*floatBuffer_, GetView().GetMatrix(), interpolation); 96 scene_->Render(*floatBuffer_, GetView().GetMatrix(), interpolation);
60 97
61 // Conversion from Float32 to BGRA32 (cairo). Very similar to 98 // Conversion from Float32 to BGRA32 (cairo). Very similar to
62 // GrayscaleFrameRenderer => TODO MERGE? 99 // GrayscaleFrameRenderer => TODO MERGE?
63 100
64 Orthanc::ImageAccessor target; 101 Orthanc::ImageAccessor target;
65 cairoBuffer_->GetWriteableAccessor(target); 102 cairoBuffer_->GetWriteableAccessor(target);
66 103
67 float scaling = 255.0f / (x1 - x0); 104 float scaling = 255.0f / (x1 - x0);
68 105
106 bool invert = IsInvertedInternal();
107
69 for (unsigned int y = 0; y < height; y++) 108 for (unsigned int y = 0; y < height; y++)
70 { 109 {
71 const float* p = reinterpret_cast<const float*>(floatBuffer_->GetConstRow(y)); 110 const float* p = reinterpret_cast<const float*>(floatBuffer_->GetConstRow(y));
72 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y)); 111 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
73 112
86 { 125 {
87 // https://en.wikipedia.org/wiki/Linear_interpolation 126 // https://en.wikipedia.org/wiki/Linear_interpolation
88 v = static_cast<uint8_t>(scaling * (*p - x0)); // (*) 127 v = static_cast<uint8_t>(scaling * (*p - x0)); // (*)
89 } 128 }
90 129
91 if (invert_) 130 if (invert)
92 { 131 {
93 v = 255 - v; 132 v = 255 - v;
94 } 133 }
95 134
96 q[0] = v; 135 q[0] = v;
170 } 209 }
171 210
172 211
173 void RadiographyWidget::OnGeometryChanged(const RadiographyScene::GeometryChangedMessage& message) 212 void RadiographyWidget::OnGeometryChanged(const RadiographyScene::GeometryChangedMessage& message)
174 { 213 {
175 LOG(INFO) << "Geometry has changed"; 214 LOG(INFO) << "Scene geometry has changed";
215
176 FitContent(); 216 FitContent();
177 } 217 }
178 218
179 219
180 void RadiographyWidget::OnContentChanged(const RadiographyScene::ContentChangedMessage& message) 220 void RadiographyWidget::OnContentChanged(const RadiographyScene::ContentChangedMessage& message)
181 { 221 {
182 LOG(INFO) << "Content has changed"; 222 LOG(INFO) << "Scene content has changed";
183 NotifyContentChanged(); 223 NotifyContentChanged();
184 } 224 }
185 225
186 226
187 void RadiographyWidget::SetInvert(bool invert) 227 void RadiographyWidget::SetInvert(bool invert)
218 } 258 }
219 259
220 scene_ = scene; 260 scene_ = scene;
221 261
222 scene_->RegisterObserverCallback( 262 scene_->RegisterObserverCallback(
223 new Callable<RadiographyWidget, RadiographyScene::GeometryChangedMessage> 263 new Callable<RadiographyWidget, RadiographyScene::GeometryChangedMessage>
224 (*this, &RadiographyWidget::OnGeometryChanged)); 264 (*this, &RadiographyWidget::OnGeometryChanged));
225 265
226 scene_->RegisterObserverCallback( 266 scene_->RegisterObserverCallback(
227 new Callable<RadiographyWidget, RadiographyScene::ContentChangedMessage> 267 new Callable<RadiographyWidget, RadiographyScene::ContentChangedMessage>
228 (*this, &RadiographyWidget::OnContentChanged)); 268 (*this, &RadiographyWidget::OnContentChanged));
269
270 NotifyContentChanged();
229 271
230 // force redraw 272 // force redraw
231 FitContent(); 273 FitContent();
232 } 274 }
233 } 275 }