39 #include <visp3/core/vpConfig.h>
41 #if defined _MSC_VER && _MSC_VER >= 1200
51 #include <visp3/core/vpMeterPixelConversion.h>
52 #include <visp3/mbt/vpMbScanLine.h>
54 #if defined(DEBUG_DISP)
55 #include <visp3/gui/vpDisplayGDI.h>
56 #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(), visibility_samples(), depthTreshold(1e-06)
63 #if defined(DEBUG_DISP)
65 dispMaskDebug(nullptr), dispLineDebug(nullptr), linedebugImg()
68 #if defined(VISP_HAVE_X11) && defined(DEBUG_DISP)
69 dispLineDebug =
new vpDisplayX();
70 dispMaskDebug =
new vpDisplayX();
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 !=
nullptr)
82 if (dispMaskDebug !=
nullptr)
96 void vpMbScanLine::drawLineY(
const vpColVector &a,
const vpColVector &b,
const vpMbScanLineEdge &edge,
const int ID,
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];
112 if (y0 >= h - 1 || y1 < 0 || std::fabs(y1 - y0) <= std::numeric_limits<double>::epsilon())
115 const unsigned int _y0 = std::max<unsigned int>((
unsigned int)0, (
unsigned int)(std::ceil(y0)));
116 const double _y1 = std::min<double>((
double)h, (
double)y1);
118 const bool b_sample_Y = (std::fabs(y0 - y1) > std::fabs(x0 - x1));
120 for (
unsigned int y = _y0; y < _y1; ++y) {
121 double x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
122 const double alpha = getAlpha(y, y0 * z0, z0, y1 * z1, z1);
123 vpMbScanLineSegment s;
126 s.Z2 = s.Z1 = mix(z0, z1, alpha);
127 s.P2 = s.P1 = s.p * s.Z1;
130 s.b_sample_Y = b_sample_Y;
131 scanlines[y].push_back(s);
145 void vpMbScanLine::drawLineX(
const vpColVector &a,
const vpColVector &b,
const vpMbScanLineEdge &edge,
const int ID,
146 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
148 double x0 = a[0] / a[2];
149 double y0 = a[1] / a[2];
151 double x1 = b[0] / b[2];
152 double y1 = b[1] / b[2];
161 if (x0 >= w - 1 || x1 < 0 || std::fabs(x1 - x0) <= std::numeric_limits<double>::epsilon())
164 const unsigned int _x0 = std::max<unsigned int>((
unsigned int)0, (
unsigned int)(std::ceil(x0)));
165 const double _x1 = std::min<double>((
double)w, (
double)x1);
167 const bool b_sample_Y = (std::fabs(y0 - y1) > std::fabs(x0 - x1));
169 for (
unsigned int x = _x0; x < _x1; ++x) {
170 double y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
171 const double alpha = getAlpha(x, x0 * z0, z0, x1 * z1, z1);
172 vpMbScanLineSegment s;
175 s.Z2 = s.Z1 = mix(z0, z1, alpha);
176 s.P2 = s.P1 = s.p * s.Z1;
179 s.b_sample_Y = b_sample_Y;
180 scanlines[x].push_back(s);
191 void vpMbScanLine::drawPolygonY(
const std::vector<std::pair<vpPoint, unsigned int> > &polygon,
const int ID,
192 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
194 if (polygon.size() < 2)
197 if (polygon.size() == 2) {
199 createVectorFromPoint(polygon.front().first, p1, K);
200 createVectorFromPoint(polygon.back().first, p2, K);
202 drawLineY(p1, p2, makeMbScanLineEdge(polygon.front().first, polygon.back().first), ID, scanlines);
206 std::vector<std::vector<vpMbScanLineSegment> > local_scanlines;
207 local_scanlines.resize(h);
209 for (
size_t i = 0; i < polygon.size(); ++i) {
211 createVectorFromPoint(polygon[i].first, p1, K);
212 createVectorFromPoint(polygon[(i + 1) % polygon.size()].first, p2, K);
214 drawLineY(p1, p2, makeMbScanLineEdge(polygon[i].first, polygon[(i + 1) % polygon.size()].first), ID,
218 createScanLinesFromLocals(scanlines, local_scanlines, h);
228 void vpMbScanLine::drawPolygonX(
const std::vector<std::pair<vpPoint, unsigned int> > &polygon,
const int ID,
229 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
231 if (polygon.size() < 2)
234 if (polygon.size() == 2) {
236 createVectorFromPoint(polygon.front().first, p1, K);
237 createVectorFromPoint(polygon.back().first, p2, K);
239 drawLineX(p1, p2, makeMbScanLineEdge(polygon.front().first, polygon.back().first), ID, scanlines);
243 std::vector<std::vector<vpMbScanLineSegment> > local_scanlines;
244 local_scanlines.resize(w);
246 for (
size_t i = 0; i < polygon.size(); ++i) {
248 createVectorFromPoint(polygon[i].first, p1, K);
249 createVectorFromPoint(polygon[(i + 1) % polygon.size()].first, p2, K);
251 drawLineX(p1, p2, makeMbScanLineEdge(polygon[i].first, polygon[(i + 1) % polygon.size()].first), ID,
255 createScanLinesFromLocals(scanlines, local_scanlines, w);
267 void vpMbScanLine::createScanLinesFromLocals(std::vector<std::vector<vpMbScanLineSegment> > &scanlines,
268 std::vector<std::vector<vpMbScanLineSegment> > &localScanlines,
269 const unsigned int &size)
271 for (
unsigned int j = 0; j < size; ++j) {
272 std::vector<vpMbScanLineSegment> &scanline = localScanlines[j];
273 sort(scanline.begin(), scanline.end(),
274 vpMbScanLineSegmentComparator());
277 for (
size_t i = 0; i < scanline.size(); ++i) {
278 vpMbScanLineSegment s = scanline[i];
285 vpMbScanLineSegment &prev = scanlines[j].back();
294 scanlines[j].push_back(s);
308 void vpMbScanLine::drawScene(
const std::vector<std::vector<std::pair<vpPoint, unsigned int> > *> &polygons,
316 visibility_samples.clear();
318 std::vector<std::vector<vpMbScanLineSegment> > scanlinesY;
319 scanlinesY.resize(h);
320 std::vector<std::vector<vpMbScanLineSegment> > scanlinesX;
321 scanlinesX.resize(w);
323 mask.resize(h, w, 0);
328 primitive_ids.resize(h, w, -1);
330 for (
unsigned int ID = 0; ID < polygons.size(); ++ID) {
331 drawPolygonY(*(polygons[ID]), listPolyIndices[ID], scanlinesY);
332 drawPolygonX(*(polygons[ID]), listPolyIndices[ID], scanlinesX);
337 vpMbScanLineSegment last_visible;
338 for (
unsigned int y = 0; y < scanlinesY.size(); ++y) {
339 std::vector<vpMbScanLineSegment> &scanline = scanlinesY[y];
340 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
342 std::vector<std::pair<double, vpMbScanLineSegment> > stack;
343 for (
size_t i = 0; i < scanline.size(); ++i) {
344 const vpMbScanLineSegment &s = scanline[i];
348 stack.push_back(std::make_pair(s.Z1, s));
351 for (
size_t j = 0; j < stack.size(); ++j)
352 if (stack[j].second.ID == s.ID) {
353 if (j != stack.size() - 1)
354 stack[j] = stack.back();
363 for (
size_t j = 0; j < stack.size(); ++j) {
364 const vpMbScanLineSegment &s0 = stack[j].second;
365 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));
367 sort(stack.begin(), stack.end(), vpMbScanLineSegmentComparator());
369 int new_ID = stack.empty() ? -1 : stack.front().second.ID;
371 if (new_ID != last_ID || s.type == POINT) {
375 if (new_ID == -1 || s.Z1 - depthTreshold <= stack.front().first)
376 visibility_samples[s.edge].insert((
int)y);
380 visibility_samples[s.edge].insert((
int)y);
384 visibility_samples[s.edge].insert((
int)y);
390 const unsigned int x0 = std::max<unsigned int>((
unsigned int)0, (
unsigned int)(std::ceil(last_visible.p)));
391 double x1 = std::min<double>((
double)w, (
double)s.p);
392 for (
unsigned int x = x0 + maskBorder; x < x1 - maskBorder; ++x) {
393 primitive_ids[(
unsigned int)y][(
unsigned int)x] = last_visible.ID;
396 maskY[(
unsigned int)y][(
unsigned int)x] = 255;
398 mask[(
unsigned int)y][(
unsigned int)x] = 255;
403 if (!stack.empty()) {
404 last_visible = stack.front().second;
405 last_visible.p = s.p;
413 for (
unsigned int x = 0; x < scanlinesX.size(); ++x) {
414 std::vector<vpMbScanLineSegment> &scanline = scanlinesX[x];
415 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
417 std::vector<std::pair<double, vpMbScanLineSegment> > stack;
418 for (
size_t i = 0; i < scanline.size(); ++i) {
419 const vpMbScanLineSegment &s = scanline[i];
423 stack.push_back(std::make_pair(s.Z1, s));
426 for (
size_t j = 0; j < stack.size(); ++j)
427 if (stack[j].second.ID == s.ID) {
428 if (j != stack.size() - 1)
429 stack[j] = stack.back();
438 for (
size_t j = 0; j < stack.size(); ++j) {
439 const vpMbScanLineSegment &s0 = stack[j].second;
440 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));
442 sort(stack.begin(), stack.end(), vpMbScanLineSegmentComparator());
444 int new_ID = stack.empty() ? -1 : stack.front().second.ID;
446 if (new_ID != last_ID || s.type == POINT) {
450 if (new_ID == -1 || s.Z1 - depthTreshold <= stack.front().first)
451 visibility_samples[s.edge].insert((
int)x);
455 visibility_samples[s.edge].insert((
int)x);
459 visibility_samples[s.edge].insert((
int)x);
464 if (maskBorder != 0 && last_ID != -1) {
465 const unsigned int y0 = std::max<unsigned int>((
unsigned int)0, (
unsigned int)(std::ceil(last_visible.p)));
466 double y1 = std::min<double>((
double)h, (
double)s.p);
467 for (
unsigned int y = y0 + maskBorder; y < y1 - maskBorder; ++y) {
470 maskX[(
unsigned int)y][(
unsigned int)x] = 255;
475 if (!stack.empty()) {
476 last_visible = stack.front().second;
477 last_visible.p = s.p;
484 for (
unsigned int i = 0; i < h; i++)
485 for (
unsigned int j = 0; j < w; j++)
486 if (maskX[i][j] == 255 && maskY[i][j] == 255)
489 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
490 if (!dispMaskDebug->isInitialised()) {
491 dispMaskDebug->init(mask, 800, 600);
496 for (
unsigned int ID = 0; ID < polygons.size(); ++ID) {
497 for (
unsigned int i = 0; i < polygons[ID]->size(); i++) {
498 vpPoint p1 = (*(polygons[ID]))[i].first;
499 vpPoint p2 = (*(polygons[ID]))[(i + 1) % polygons[ID]->size()].first;
500 double i1 = 0, j1 = 0, i2 = 0, j2 = 0;
512 if (!dispLineDebug->isInitialised()) {
513 linedebugImg.resize(h, w, 0);
514 dispLineDebug->init(linedebugImg, 800, 100);
530 void vpMbScanLine::queryLineVisibility(
const vpPoint &a,
const vpPoint &b,
531 std::vector<std::pair<vpPoint, vpPoint> > &lines,
const bool &displayResults)
534 createVectorFromPoint(a, _a, K);
535 createVectorFromPoint(b, _b, K);
537 double x0 = _a[0] / _a[2];
538 double y0 = _a[1] / _a[2];
540 double x1 = _b[0] / _b[2];
541 double y1 = _b[1] / _b[2];
544 vpMbScanLineEdge edge = makeMbScanLineEdge(a, b);
547 if (displayResults) {
548 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
549 double i1(0.0), j1(0.0), i2(0.0), j2(0.0);
560 if (!visibility_samples.count(edge))
565 double *v0(&x0), *w0(&z0);
566 double *v1(&x1), *w1(&z1);
567 unsigned int size(w);
569 if (std::fabs(y0 - y1) > std::fabs(x0 - x1))
596 if (*v0 >= size - 1 || *v1 < 0 || std::fabs(*v1 - *v0) <= std::numeric_limits<double>::epsilon())
599 const int _v0 = std::max<int>(0,
int(std::ceil(*v0)));
600 const int _v1 = std::min<int>((
int)(size - 1), (
int)(std::ceil(*v1) - 1));
602 const std::set<int> &visible_samples = visibility_samples[edge];
606 bool b_line_started =
false;
607 for (std::set<int>::const_iterator it = visible_samples.begin(); it != visible_samples.end(); ++it) {
609 const double alpha = getAlpha(v, (*v0) * (*w0), (*w0), (*v1) * (*w1), (*w1));
611 const vpPoint p = mix(a_, b_, alpha);
614 lines.push_back(std::make_pair(line_start, line_end));
615 b_line_started =
false;
621 b_line_started =
true;
628 b_line_started =
true;
634 b_line_started =
true;
639 lines.push_back(std::make_pair(line_start, line_end));
641 if (displayResults) {
642 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
643 double i1(0.0), j1(0.0), i2(0.0), j2(0.0);
644 for (
unsigned int i = 0; i < lines.size(); i++) {
645 lines[i].first.project();
646 lines[i].second.project();
665 vpMbScanLine::vpMbScanLineEdge vpMbScanLine::makeMbScanLineEdge(
const vpPoint &a,
const vpPoint &b)
670 _a[0] = std::ceil((a.
get_X() * 1e8) * 1e-6);
671 _a[1] = std::ceil((a.
get_Y() * 1e8) * 1e-6);
672 _a[2] = std::ceil((a.
get_Z() * 1e8) * 1e-6);
674 _b[0] = std::ceil((b.
get_X() * 1e8) * 1e-6);
675 _b[1] = std::ceil((b.
get_Y() * 1e8) * 1e-6);
676 _b[2] = std::ceil((b.
get_Z() * 1e8) * 1e-6);
679 for (
unsigned int i = 0; i < 3; ++i)
684 else if (_a[i] > _b[i])
688 return std::make_pair(_a, _b);
690 return std::make_pair(_b, _a);
718 double vpMbScanLine::getAlpha(
double x,
double X0,
double Z0,
double X1,
double Z1)
720 const double N = X0 - x * Z0;
721 const double D = x * (Z1 - Z0) - (X1 - X0);
722 double alpha = N / D;
726 alpha = std::min<double>(1.0, alpha);
727 alpha = std::max<double>(0.0, alpha);
740 double vpMbScanLine::mix(
double a,
double b,
double alpha) {
return a + (b - a) * alpha; }
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
static const vpColor yellow
Display for windows using GDI (available on any windows 32 platform).
static void display(const vpImage< unsigned char > &I)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void flush(const vpImage< unsigned char > &I)
static bool isNaN(double value)
static double sqr(double x)
static bool isInf(double value)
static void convertPoint(const vpCameraParameters &cam, const double &x, const double &y, double &u, double &v)
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
double get_y() const
Get the point y coordinate in the image plane.
double get_Y() const
Get the point cY coordinate in the camera frame.
void set_X(double cX)
Set the point cX coordinate in the camera frame.
double get_x() const
Get the point x coordinate in the image plane.
void set_Y(double cY)
Set the point cY coordinate in the camera frame.
double get_Z() const
Get the point cZ coordinate in the camera frame.
void set_Z(double cZ)
Set the point cZ coordinate in the camera frame.
double get_X() const
Get the point cX coordinate in the camera frame.