Mercurial > hg > orthanc-stone
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 } |