Mercurial > hg > orthanc-stone
comparison Framework/Radiography/RadiographyMaskLayer.cpp @ 476:a95090305dd4 am-touch-events
Introduced ControlPoint instead of Corner in the trackers and layers + drawing mask from the ControlPoints
author | am@osimis.io |
---|---|
date | Wed, 13 Feb 2019 12:04:02 +0100 |
parents | 3c28542229a3 |
children | baf8c8d68bbc |
comparison
equal
deleted
inserted
replaced
475:3c28542229a3 | 476:a95090305dd4 |
---|---|
27 #include "Core/Images/ImageProcessing.h" | 27 #include "Core/Images/ImageProcessing.h" |
28 #include <Core/OrthancException.h> | 28 #include <Core/OrthancException.h> |
29 | 29 |
30 namespace OrthancStone | 30 namespace OrthancStone |
31 { | 31 { |
32 const unsigned char IN_MASK_VALUE = 0x00; | |
33 const unsigned char OUT_MASK_VALUE = 0xFF; | |
34 | |
35 const AffineTransform2D& RadiographyMaskLayer::GetTransform() const | |
36 { | |
37 return dicomLayer_.GetTransform(); | |
38 } | |
39 | |
40 const AffineTransform2D& RadiographyMaskLayer::GetTransformInverse() const | |
41 { | |
42 return dicomLayer_.GetTransformInverse(); | |
43 } | |
32 | 44 |
33 void ComputeMaskExtent(unsigned int& left, unsigned int& right, unsigned int& top, unsigned int& bottom, const std::vector<MaskPoint>& corners) | 45 void ComputeMaskExtent(unsigned int& left, unsigned int& right, unsigned int& top, unsigned int& bottom, const std::vector<MaskPoint>& corners) |
34 { | 46 { |
35 left = std::numeric_limits<unsigned int>::max(); | 47 left = std::numeric_limits<unsigned int>::max(); |
36 right = std::numeric_limits<unsigned int>::min(); | 48 right = std::numeric_limits<unsigned int>::min(); |
64 { | 76 { |
65 mask_.reset(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, dicomLayer_.GetWidth(), dicomLayer_.GetHeight(), false)); | 77 mask_.reset(new Orthanc::Image(Orthanc::PixelFormat_Grayscale8, dicomLayer_.GetWidth(), dicomLayer_.GetHeight(), false)); |
66 | 78 |
67 DrawMask(); | 79 DrawMask(); |
68 | 80 |
69 // for (unsigned int i = 0; i < 100; i++) | |
70 // { | |
71 // for (unsigned int j = 0; j < 50; j++) | |
72 // { | |
73 // if ((i + j) % 2 == 1) | |
74 // { | |
75 // Orthanc::ImageAccessor region; | |
76 // mask_->GetRegion(region, i* 20, j * 20, 20, 20); | |
77 // Orthanc::ImageProcessing::Set(region, 255); | |
78 // } | |
79 // } | |
80 // } | |
81 invalidated_ = false; | 81 invalidated_ = false; |
82 } | 82 } |
83 | 83 |
84 {// rendering | 84 {// rendering |
85 if (buffer.GetFormat() != Orthanc::PixelFormat_Float32) | 85 if (buffer.GetFormat() != Orthanc::PixelFormat_Float32) |
110 float *q = reinterpret_cast<float*>(buffer.GetRow(y)); | 110 float *q = reinterpret_cast<float*>(buffer.GetRow(y)); |
111 const uint8_t *p = reinterpret_cast<uint8_t*>(tmp.GetRow(y)); | 111 const uint8_t *p = reinterpret_cast<uint8_t*>(tmp.GetRow(y)); |
112 | 112 |
113 for (unsigned int x = 0; x < width; x++, p++, q++) | 113 for (unsigned int x = 0; x < width; x++, p++, q++) |
114 { | 114 { |
115 if (*p == 0) | 115 if (*p == OUT_MASK_VALUE) |
116 *q = foreground_; | 116 *q = foreground_; |
117 // else keep the underlying pixel value | 117 // else keep the underlying pixel value |
118 } | 118 } |
119 } | 119 } |
120 | 120 |
212 | 212 |
213 // Return true if count is odd, false otherwise | 213 // Return true if count is odd, false otherwise |
214 return count&1; // Same as (count%2 == 1) | 214 return count&1; // Same as (count%2 == 1) |
215 } | 215 } |
216 | 216 |
217 void RadiographyMaskLayer::DrawLine(const MaskPoint& start, const MaskPoint& end) const | |
218 { | |
219 int dx = (int)(end.x) - (int)(start.x); | |
220 int dy = (int)(end.y) - (int)(start.y); | |
221 | |
222 if (std::abs(dx) > std::abs(dy)) | |
223 { // the line is closer to horizontal | |
224 | |
225 int incx = dx / std::abs(dx); | |
226 double incy = (double)(dy)/(double)(dx); | |
227 double y = (double)(start.y); | |
228 for (int x = (int)(start.x); x != (int)(end.x); x += incx, y += incy) | |
229 { | |
230 unsigned char* p = reinterpret_cast<unsigned char*>(mask_->GetRow((int)(y + 0.5))) + x; | |
231 *p = IN_MASK_VALUE; | |
232 } | |
233 } | |
234 else | |
235 { // the line is closer to vertical | |
236 int incy = dy / std::abs(dy); | |
237 double incx = (double)(dx)/(double)(dy); | |
238 double x = (double)(start.x); | |
239 for (int y = (int)(start.y); y != (int)(end.y); y += incy, x += incx) | |
240 { | |
241 unsigned char* p = reinterpret_cast<unsigned char*>(mask_->GetRow(y)) + (int)(x + 0.5); | |
242 *p = IN_MASK_VALUE; | |
243 } | |
244 } | |
245 } | |
246 | |
217 | 247 |
218 void RadiographyMaskLayer::DrawMask() const | 248 void RadiographyMaskLayer::DrawMask() const |
219 { | 249 { |
220 unsigned int left; | 250 unsigned int left; |
221 unsigned int right; | 251 unsigned int right; |
222 unsigned int top; | 252 unsigned int top; |
223 unsigned int bottom; | 253 unsigned int bottom; |
224 | 254 |
225 ComputeMaskExtent(left, right, top, bottom, corners_); | 255 // ComputeMaskExtent(left, right, top, bottom, corners_); |
226 | 256 |
227 Orthanc::ImageProcessing::Set(*mask_, 0); | 257 left = 0; |
228 | 258 right = 2500; |
229 MaskPoint p(left, top); | 259 top = 0; |
230 for (p.y = top; p.y <= bottom; p.y++) | 260 bottom = 2500; |
261 // first fill the complete image | |
262 Orthanc::ImageProcessing::Set(*mask_, OUT_MASK_VALUE); | |
263 | |
264 | |
231 { | 265 { |
232 unsigned char* q = reinterpret_cast<unsigned char*>(mask_->GetRow(p.y)); | 266 // from http://alienryderflex.com/polygon_fill/ |
233 for (p.x = left; p.x <= right; p.x++, q++) | 267 std::auto_ptr<int> raiiNodeX(new int(corners_.size())); |
234 { | 268 |
235 if (isInside(corners_, p)) | 269 std::vector<int> nodeX; |
270 nodeX.resize(corners_.size()); | |
271 int nodes, pixelX, pixelY, i, j, swap ; | |
272 | |
273 // Loop through the rows of the image. | |
274 for (pixelY = (int)top; pixelY < (int)bottom; pixelY++) | |
275 { | |
276 // Build a list of nodes. | |
277 nodes = 0; | |
278 j = (int)corners_.size() - 1; | |
279 | |
280 for (i = 0; i < (int)corners_.size(); i++) | |
236 { | 281 { |
237 *q = 255; | 282 if ((int)corners_[i].y < pixelY && (int)corners_[j].y >= pixelY |
283 || (int)corners_[j].y < pixelY && (int)corners_[i].y >= pixelY) | |
284 { | |
285 nodeX[nodes++]= (int)((double)corners_[i].x + ((double)pixelY - (double)corners_[i].y)/((double)corners_[j].y - (double)corners_[i].y) *((double)corners_[j].x - (double)corners_[i].x)); | |
286 } | |
287 j=i; | |
238 } | 288 } |
239 } | 289 |
240 } | 290 // Sort the nodes, via a simple “Bubble” sort. |
241 | 291 i=0; |
242 // Orthanc::ImageAccessor region; | 292 while (i<nodes-1) |
243 // mask_->GetRegion(region, 100, 100, 1000, 1000); | 293 { |
244 // Orthanc::ImageProcessing::Set(region, 255); | 294 if (nodeX[i]>nodeX[i+1]) |
295 { | |
296 swap=nodeX[i]; nodeX[i]=nodeX[i+1]; nodeX[i+1]=swap; if (i) i--; | |
297 } | |
298 else | |
299 { | |
300 i++; | |
301 } | |
302 } | |
303 | |
304 unsigned char* row = reinterpret_cast<unsigned char*>(mask_->GetRow(pixelY)); | |
305 // Fill the pixels between node pairs. | |
306 for (i=0; i<nodes; i+=2) | |
307 { | |
308 if (nodeX[i ]>=(int)right) | |
309 break; | |
310 if (nodeX[i+1]> (int)left) | |
311 { | |
312 if (nodeX[i ]< (int)left ) | |
313 nodeX[i ]=(int)left ; | |
314 if (nodeX[i+1]> (int)right) | |
315 nodeX[i+1]=(int)right; | |
316 for (pixelX=nodeX[i]; pixelX<nodeX[i+1]; pixelX++) | |
317 { | |
318 *(row + pixelX) = IN_MASK_VALUE; | |
319 } | |
320 } | |
321 } | |
322 } | |
323 } | |
324 | |
325 // // draw lines | |
326 // for (size_t i = 1; i < corners_.size(); i++) | |
327 // { | |
328 // DrawLine(corners_[i-1], corners_[i]); | |
329 // } | |
330 // DrawLine(corners_[corners_.size()-1], corners_[0]); | |
331 | |
332 // // fill between lines | |
333 // MaskPoint p(left, top); | |
334 // for (p.y = top; p.y <= bottom; p.y++) | |
335 // { | |
336 // unsigned char* q = reinterpret_cast<unsigned char*>(mask_->GetRow(p.y)) + left; | |
337 // unsigned char previousPixelValue1 = OUT_MASK_VALUE; | |
338 // unsigned char previousPixelValue2 = OUT_MASK_VALUE; | |
339 // for (p.x = left; p.x <= right; p.x++, q++) | |
340 // { | |
341 // if (*p == OUT_MASK_VALUE && previousPixelValue1 == IN_MASK_VALUE && previousPixelValue2 == OUT_MASK_VALUE) // we just passed over a single one pixel line => start filling | |
342 // { | |
343 | |
344 // *q = IN_MASK_VALUE; | |
345 // } | |
346 // } | |
347 // } | |
348 | |
349 | |
350 // MaskPoint p(left, top); | |
351 // for (p.y = top; p.y <= bottom; p.y++) | |
352 // { | |
353 // unsigned char* q = reinterpret_cast<unsigned char*>(mask_->GetRow(p.y)) + left; | |
354 // for (p.x = left; p.x <= right; p.x++, q++) | |
355 // { | |
356 // if (isInside(corners_, p)) | |
357 // { | |
358 // *q = IN_MASK_VALUE; | |
359 // } | |
360 // } | |
361 // } | |
362 | |
245 } | 363 } |
246 | 364 |
247 } | 365 } |