38 #include <visp3/core/vpConfig.h>
40 #if defined _MSC_VER && _MSC_VER >= 1200
50 #include <visp3/mbt/vpMbScanLine.h>
51 #include <visp3/core/vpMeterPixelConversion.h>
53 #if defined(DEBUG_DISP)
54 #include <visp3/gui/vpDisplayGDI.h>
55 #include <visp3/gui/vpDisplayX.h>
59 #ifndef DOXYGEN_SHOULD_SKIP_THIS
61 vpMbScanLine::vpMbScanLine()
62 : w(0), h(0), K(), maskBorder(0), mask(), primitive_ids(),
63 visibility_samples(), depthTreshold(1e-06)
64 #if defined(DEBUG_DISP)
65 ,dispMaskDebug(NULL), dispLineDebug(NULL), linedebugImg()
68 #if defined(VISP_HAVE_X11) && defined(DEBUG_DISP)
71 #elif defined(VISP_HAVE_GDI) && defined(DEBUG_DISP)
77 vpMbScanLine::~vpMbScanLine()
79 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
80 if (dispLineDebug != NULL)
delete dispLineDebug;
81 if (dispMaskDebug != NULL)
delete dispMaskDebug;
95 const vpMbScanLineEdge &edge,
97 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
99 double x0 = a[0] / a[2];
100 double y0 = a[1] / a[2];
102 double x1 = b[0] / b[2];
103 double y1 = b[1] / b[2];
113 if (y0 >= h - 1 || y1 < 0 || std::fabs(y1 - y0) <= std::numeric_limits<double>::epsilon())
116 const unsigned int _y0 = std::max<unsigned int>(0, (
unsigned int)(std::ceil(y0)));
117 const double _y1 = std::min<double>(h, y1);
119 const bool b_sample_Y = (std::fabs(y0 - y1) > std::fabs(x0 - x1));
121 for(
unsigned int y = _y0 ; y < _y1 ; ++y)
123 const double x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
124 const double alpha = getAlpha(y, y0 * z0, z0, y1 * z1, z1);
125 vpMbScanLineSegment s;
128 s.Z2 = s.Z1 = mix(z0, z1, alpha);
129 s.P2 = s.P1 = s.p * s.Z1;
132 s.b_sample_Y = b_sample_Y;
133 scanlines[y].push_back(s);
148 const vpMbScanLineEdge &edge,
150 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
152 double x0 = a[0] / a[2];
153 double y0 = a[1] / a[2];
155 double x1 = b[0] / b[2];
156 double y1 = b[1] / b[2];
166 if (x0 >= w - 1 || x1 < 0 || std::fabs(x1 - x0) <= std::numeric_limits<double>::epsilon())
169 const unsigned int _x0 = std::max<unsigned int>(0, (
unsigned int)(std::ceil(x0)));
170 const double _x1 = std::min<double>(w, x1);
172 const bool b_sample_Y = (std::fabs(y0 - y1) > std::fabs(x0 - x1));
174 for(
unsigned int x = _x0 ; x < _x1 ; ++x)
176 const double y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
177 const double alpha = getAlpha(x, x0 * z0, z0, x1 * z1, z1);
178 vpMbScanLineSegment s;
181 s.Z2 = s.Z1 = mix(z0, z1, alpha);
182 s.P2 = s.P1 = s.p * s.Z1;
185 s.b_sample_Y = b_sample_Y;
186 scanlines[x].push_back(s);
199 vpMbScanLine::drawPolygonY(
const std::vector<std::pair<vpPoint, unsigned int> > &polygon,
201 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
203 if (polygon.size() < 2)
206 if (polygon.size() == 2)
209 createVectorFromPoint(polygon.front().first, p1, K);
210 createVectorFromPoint(polygon.back().first, p2, K);
214 makeMbScanLineEdge(polygon.front().first, polygon.back().first),
220 std::vector<std::vector<vpMbScanLineSegment> > local_scanlines;
221 local_scanlines.resize(h);
223 for(
size_t i = 0 ; i < polygon.size() ; ++i)
226 createVectorFromPoint(polygon[i].first, p1, K);
227 createVectorFromPoint(polygon[(i + 1) % polygon.size()].first, p2, K);
229 drawLineY(p1, p2, makeMbScanLineEdge(polygon[i].first, polygon[(i + 1) % polygon.size()].first), ID, local_scanlines);
232 createScanLinesFromLocals(scanlines,local_scanlines,h);
243 vpMbScanLine::drawPolygonX(
const std::vector<std::pair<vpPoint, unsigned int> > &polygon,
245 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
247 if (polygon.size() < 2)
250 if (polygon.size() == 2)
253 createVectorFromPoint(polygon.front().first, p1, K);
254 createVectorFromPoint(polygon.back().first, p2, K);
258 makeMbScanLineEdge(polygon.front().first, polygon.back().first),
264 std::vector<std::vector<vpMbScanLineSegment> > local_scanlines;
265 local_scanlines.resize(w);
267 for(
size_t i = 0 ; i < polygon.size() ; ++i)
270 createVectorFromPoint(polygon[i].first, p1, K);
271 createVectorFromPoint(polygon[(i + 1) % polygon.size()].first, p2, K);
273 drawLineX(p1, p2, makeMbScanLineEdge(polygon[i].first, polygon[(i + 1) % polygon.size()].first), ID, local_scanlines);
276 createScanLinesFromLocals(scanlines,local_scanlines,w);
289 vpMbScanLine::createScanLinesFromLocals(std::vector<std::vector<vpMbScanLineSegment> > &scanlines,
290 std::vector<std::vector<vpMbScanLineSegment> > &localScanlines,
291 const unsigned int &size)
293 for(
unsigned int j = 0 ; j < size ; ++j)
295 std::vector<vpMbScanLineSegment> &scanline = localScanlines[j];
296 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
299 for(
size_t i = 0 ; i < scanline.size() ; ++i)
301 vpMbScanLineSegment s = scanline[i];
310 vpMbScanLineSegment &prev = scanlines[j].back();
319 scanlines[j].push_back(s);
334 vpMbScanLine::drawScene(
const std::vector<std::vector<std::pair<vpPoint, unsigned int> > * > &polygons,
335 std::vector<int> listPolyIndices,
342 visibility_samples.clear();
344 std::vector<std::vector<vpMbScanLineSegment> > scanlinesY;
345 scanlinesY.resize(h);
346 std::vector<std::vector<vpMbScanLineSegment> > scanlinesX;
347 scanlinesX.resize(w);
354 primitive_ids.resize(h, w, -1);
356 for(
unsigned int ID = 0 ; ID < polygons.size() ; ++ID)
358 drawPolygonY(*(polygons[ID]), listPolyIndices[ID], scanlinesY);
359 drawPolygonX(*(polygons[ID]), listPolyIndices[ID], scanlinesX);
364 vpMbScanLineSegment last_visible;
365 for(
unsigned int y = 0 ; y < scanlinesY.size() ; ++y)
367 std::vector<vpMbScanLineSegment> &scanline = scanlinesY[y];
368 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
370 std::vector<std::pair<double, vpMbScanLineSegment> > stack;
371 for(
size_t i = 0 ; i < scanline.size() ; ++i)
373 const vpMbScanLineSegment &s = scanline[i];
378 stack.push_back(std::make_pair(s.Z1, s));
381 for(
size_t j = 0 ; j < stack.size() ; ++j)
382 if (stack[j].second.ID == s.ID)
384 stack[j] = stack.back();
393 for(
size_t j = 0 ; j < stack.size() ; ++j)
395 const vpMbScanLineSegment &s0 = stack[j].second;
396 stack[j].first = mix(s0.Z1, s0.Z2, getAlpha(s.type == POINT ? s.p : (s.p + 0.5), s0.P1, s0.Z1, s0.P2, s0.Z2));
398 sort(stack.begin(), stack.end(), vpMbScanLineSegmentComparator());
400 int new_ID = stack.empty() ? -1 : stack.front().second.ID;
402 if (new_ID != last_ID || s.type == POINT)
408 if (new_ID == -1 || s.Z1 - depthTreshold <= stack.front().first)
409 visibility_samples[s.edge].insert((
int)y);
413 visibility_samples[s.edge].insert((
int)y);
417 visibility_samples[s.edge].insert((
int)y);
424 const unsigned int x0 = std::max<unsigned int>(0, (
unsigned int)(std::ceil(last_visible.p)));
425 const double x1 = std::min<double>(w, s.p);
426 for(
unsigned int x = x0 + maskBorder ; x < x1 - maskBorder; ++x)
428 primitive_ids[(
unsigned int)y][(
unsigned int)x] = last_visible.ID;
431 maskY[(
unsigned int)y][(
unsigned int)x] = 255;
433 mask[(
unsigned int)y][(
unsigned int)x] = 255;
440 last_visible = stack.front().second;
441 last_visible.p = s.p;
449 for(
unsigned int x = 0 ; x < scanlinesX.size() ; ++x)
451 std::vector<vpMbScanLineSegment> &scanline = scanlinesX[x];
452 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
454 std::vector<std::pair<double, vpMbScanLineSegment> > stack;
455 for(
size_t i = 0 ; i < scanline.size() ; ++i)
457 const vpMbScanLineSegment &s = scanline[i];
462 stack.push_back(std::make_pair(s.Z1, s));
465 for(
size_t j = 0 ; j < stack.size() ; ++j)
466 if (stack[j].second.ID == s.ID)
468 stack[j] = stack.back();
477 for(
size_t j = 0 ; j < stack.size() ; ++j)
479 const vpMbScanLineSegment &s0 = stack[j].second;
480 stack[j].first = mix(s0.Z1, s0.Z2, getAlpha(s.type == POINT ? s.p : (s.p + 0.5), s0.P1, s0.Z1, s0.P2, s0.Z2));
482 sort(stack.begin(), stack.end(), vpMbScanLineSegmentComparator());
484 int new_ID = stack.empty() ? -1 : stack.front().second.ID;
486 if (new_ID != last_ID || s.type == POINT)
492 if (new_ID == -1 || s.Z1 - depthTreshold <= stack.front().first)
493 visibility_samples[s.edge].insert((
int)x);
497 visibility_samples[s.edge].insert((
int)x);
501 visibility_samples[s.edge].insert((
int)x);
506 if (maskBorder != 0 && last_ID != -1)
508 const unsigned int y0 = std::max<unsigned int>(0, (
unsigned int)(std::ceil(last_visible.p)));
509 const double y1 = std::min<double>(h, s.p);
510 for(
unsigned int y = y0 + maskBorder ; y < y1 - maskBorder; ++y)
513 maskX[(
unsigned int)y][(
unsigned int)x] = 255;
520 last_visible = stack.front().second;
521 last_visible.p = s.p;
528 for(
unsigned int i = 0 ; i < h ; i++)
529 for(
unsigned int j = 0 ; j < w ; j++)
530 if(maskX[i][j] == 255 && maskY[i][j] == 255)
533 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
534 if(!dispMaskDebug->isInitialised()){
535 dispMaskDebug->init(mask, 800, 600);
540 for(
unsigned int ID = 0 ; ID < polygons.size() ; ++ID)
542 for(
unsigned int i = 0 ; i < polygons[ID]->size() ; i++){
543 vpPoint p1 = (*(polygons[ID]))[i].first;
544 vpPoint p2 = (*(polygons[ID]))[(i+1)%polygons[ID]->size()].first;
545 double i1=0,j1=0,i2=0,j2=0;
558 if(!dispLineDebug->isInitialised()){
559 linedebugImg.resize(h,w,0);
560 dispLineDebug->init(linedebugImg, 800, 100);
576 vpMbScanLine::queryLineVisibility(
const vpPoint &a,
const vpPoint &b,
577 std::vector<std::pair<vpPoint, vpPoint> > &lines,
578 const bool &displayResults)
581 createVectorFromPoint(a, _a, K);
582 createVectorFromPoint(b, _b, K);
584 double x0 = _a[0] / _a[2];
585 double y0 = _a[1] / _a[2];
587 double x1 = _b[0] / _b[2];
588 double y1 = _b[1] / _b[2];
591 vpMbScanLineEdge edge = makeMbScanLineEdge(a, b);
595 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
596 double i1(0.0), j1(0.0), i2(0.0), j2(0.0);
607 if (!visibility_samples.count(edge))
611 double *v0(&x0), *w0(&z0);
612 double *v1(&x1), *w1(&z1);
613 unsigned int size(w);
615 if (std::fabs(y0 - y1) > std::fabs(x0 - x1))
643 if (*v0 >= size - 1 || *v1 < 0 || std::fabs(*v1 - *v0) <= std::numeric_limits<double>::epsilon())
646 const int _v0 = std::max(0,
int(std::ceil(*v0)));
647 const int _v1 = std::min<int>((int)(size - 1), (int)(std::ceil(*v1) - 1));
649 const std::set<int> &visible_samples = visibility_samples[edge];
653 bool b_line_started =
false;
654 for(std::set<int>::const_iterator it = visible_samples.begin() ; it != visible_samples.end() ; ++it)
657 const double alpha = getAlpha(v, (*v0) * (*w0), (*w0), (*v1) * (*w1), (*w1));
659 const vpPoint p = mix(a_, b_, alpha);
663 lines.push_back(std::make_pair(line_start, line_end));
664 b_line_started =
false;
671 b_line_started =
true;
679 b_line_started =
true;
686 b_line_started =
true;
691 lines.push_back(std::make_pair(line_start, line_end));
694 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
695 double i1(0.0), j1(0.0), i2(0.0), j2(0.0);
696 for(
unsigned int i = 0 ; i < lines.size() ; i++){
697 lines[i].first.project();
698 lines[i].second.project();
717 vpMbScanLine::vpMbScanLineEdge
718 vpMbScanLine::makeMbScanLineEdge(
const vpPoint &a,
const vpPoint &b)
723 _a[0] = std::ceil((a.
get_X() * 1e8) * 1e-6);
724 _a[1] = std::ceil((a.
get_Y() * 1e8) * 1e-6);
725 _a[2] = std::ceil((a.
get_Z() * 1e8) * 1e-6);
727 _b[0] = std::ceil((b.
get_X() * 1e8) * 1e-6);
728 _b[1] = std::ceil((b.
get_Y() * 1e8) * 1e-6);
729 _b[2] = std::ceil((b.
get_Z() * 1e8) * 1e-6);
732 for(
unsigned int i = 0 ; i < 3 ; ++i)
738 else if(_a[i] > _b[i])
742 return std::make_pair(_a, _b);
744 return std::make_pair(_b, _a);
774 vpMbScanLine::getAlpha(
double x,
double X0,
double Z0,
double X1,
double Z1)
776 const double N = X0 - x * Z0;
777 const double D = x * (Z1 - Z0) - (X1 - X0);
778 double alpha = N / D;
782 alpha = std::min(1.0,alpha);
783 alpha = std::max(0.0,alpha);
797 vpMbScanLine::mix(
double a,
double b,
double alpha)
799 return a + (b - a) * alpha;
812 vpMbScanLine::mix(
const vpPoint &a,
const vpPoint &b,
double alpha)
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Point coordinates conversion from normalized coordinates in meter to pixel coordinates ...
static bool isNaN(const double value)
Display for windows using GDI (available on any windows 32 platform).
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
double get_y() const
Get the point y coordinate in the image plane.
static bool isInf(const double value)
void set_X(const double X)
Set the point X coordinate in the camera frame.
static void flush(const vpImage< unsigned char > &I)
Class that defines what is a point.
void set_Z(const double Z)
Set the point Z coordinate in the camera frame.
static double sqr(double x)
static void display(const vpImage< unsigned char > &I)
Generic class defining intrinsic camera parameters.
void set_Y(const double Y)
Set the point Y coordinate in the camera frame.
double get_x() const
Get the point x coordinate in the image plane.
double get_Y() const
Get the point Y coordinate in the camera frame.
double get_Z() const
Get the point Z coordinate in the camera frame.
Implementation of column vector and the associated operations.
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
static const vpColor yellow
double get_X() const
Get the point X coordinate in the camera frame.