34#include <visp3/core/vpConfig.h>
36#if defined _MSC_VER && _MSC_VER >= 1200
46#include <visp3/core/vpMeterPixelConversion.h>
47#include <visp3/mbt/vpMbScanLine.h>
49#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
50#include <visp3/gui/vpDisplayGDI.h>
51#include <visp3/gui/vpDisplayX.h>
54#ifndef DOXYGEN_SHOULD_SKIP_THIS
56vpMbScanLine::vpMbScanLine()
57 :
w(0),
h(0),
K(), maskBorder(0), mask(), primitive_ids(), visibility_samples(), depthTreshold(1
e-06)
58#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
60 dispMaskDebug(nullptr), dispLineDebug(nullptr), linedebugImg()
63#if defined(VISP_HAVE_X11) && defined(DEBUG_DISP)
66#elif defined(VISP_HAVE_GDI) && defined(DEBUG_DISP)
72vpMbScanLine::vpMbScanLine(
const vpMbScanLine &scanline)
77vpMbScanLine::~vpMbScanLine()
79#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
80 if (dispLineDebug !=
nullptr)
82 if (dispMaskDebug !=
nullptr)
88vpMbScanLine &vpMbScanLine::operator=(
const vpMbScanLine &scanline)
93 maskBorder = scanline.maskBorder;
95 primitive_ids = scanline.primitive_ids;
96 visibility_samples = scanline.visibility_samples;
97 depthTreshold = scanline.depthTreshold;
99#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
100 dispLineDebug = scanline.dispLineDebug;
101 dispMaskDebug = scanline.dispMaskDebug;
102 linedebugImg = scanline.linedebugImg;
117void vpMbScanLine::drawLineY(
const vpColVector &a,
const vpColVector &b,
const vpMbScanLineEdge &edge,
const int ID,
118 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
120 double x0 = a[0] / a[2];
121 double y0 = a[1] / a[2];
123 double x1 = b[0] / b[2];
124 double y1 = b[1] / b[2];
133 if (y0 >= h - 1 || y1 < 0 || std::fabs(y1 - y0) <= std::numeric_limits<double>::epsilon())
136 const unsigned int _y0 = std::max<unsigned int>(
static_cast<unsigned int>(0),
static_cast<unsigned int>(std::ceil(y0)));
137 const double _y1 = std::min<double>(
static_cast<double>(h),
static_cast<double>(y1));
139 const bool b_sample_Y = (std::fabs(y0 - y1) > std::fabs(x0 - x1));
141 for (
unsigned int y = _y0;
y < _y1; ++
y) {
142 double x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
143 const double alpha = getAlpha(y, y0 * z0, z0, y1 * z1, z1);
144 vpMbScanLineSegment
s;
147 s.Z2 =
s.Z1 = mix(z0, z1, alpha);
148 s.P2 =
s.P1 =
s.p *
s.Z1;
151 s.b_sample_Y = b_sample_Y;
152 scanlines[
y].push_back(s);
166void vpMbScanLine::drawLineX(
const vpColVector &a,
const vpColVector &b,
const vpMbScanLineEdge &edge,
const int ID,
167 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
169 double x0 = a[0] / a[2];
170 double y0 = a[1] / a[2];
172 double x1 = b[0] / b[2];
173 double y1 = b[1] / b[2];
182 if (x0 >= w - 1 || x1 < 0 || std::fabs(x1 - x0) <= std::numeric_limits<double>::epsilon())
185 const unsigned int _x0 = std::max<unsigned int>(
static_cast<unsigned int>(0),
static_cast<unsigned int>(std::ceil(x0)));
186 const double _x1 = std::min<double>(
static_cast<double>(w),
static_cast<double>(x1));
188 const bool b_sample_Y = (std::fabs(y0 - y1) > std::fabs(x0 - x1));
190 for (
unsigned int x = _x0;
x < _x1; ++
x) {
191 double y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
192 const double alpha = getAlpha(x, x0 * z0, z0, x1 * z1, z1);
193 vpMbScanLineSegment
s;
196 s.Z2 =
s.Z1 = mix(z0, z1, alpha);
197 s.P2 =
s.P1 =
s.p *
s.Z1;
200 s.b_sample_Y = b_sample_Y;
201 scanlines[
x].push_back(s);
212void vpMbScanLine::drawPolygonY(
const std::vector<std::pair<vpPoint, unsigned int> > &polygon,
const int ID,
213 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
215 if (polygon.size() < 2)
218 if (polygon.size() == 2) {
220 createVectorFromPoint(polygon.front().first, p1, K);
221 createVectorFromPoint(polygon.back().first, p2, K);
223 drawLineY(p1, p2, makeMbScanLineEdge(polygon.front().first, polygon.back().first), ID, scanlines);
227 std::vector<std::vector<vpMbScanLineSegment> > local_scanlines;
228 local_scanlines.resize(h);
230 for (
size_t i = 0;
i < polygon.size(); ++
i) {
232 createVectorFromPoint(polygon[i].first, p1, K);
233 createVectorFromPoint(polygon[(i + 1) % polygon.size()].first, p2, K);
235 drawLineY(p1, p2, makeMbScanLineEdge(polygon[i].first, polygon[(i + 1) % polygon.size()].first), ID,
239 createScanLinesFromLocals(scanlines, local_scanlines, h);
249void vpMbScanLine::drawPolygonX(
const std::vector<std::pair<vpPoint, unsigned int> > &polygon,
const int ID,
250 std::vector<std::vector<vpMbScanLineSegment> > &scanlines)
252 if (polygon.size() < 2)
255 if (polygon.size() == 2) {
257 createVectorFromPoint(polygon.front().first, p1, K);
258 createVectorFromPoint(polygon.back().first, p2, K);
260 drawLineX(p1, p2, makeMbScanLineEdge(polygon.front().first, polygon.back().first), ID, scanlines);
264 std::vector<std::vector<vpMbScanLineSegment> > local_scanlines;
265 local_scanlines.resize(w);
267 for (
size_t i = 0;
i < polygon.size(); ++
i) {
269 createVectorFromPoint(polygon[i].first, p1, K);
270 createVectorFromPoint(polygon[(i + 1) % polygon.size()].first, p2, K);
272 drawLineX(p1, p2, makeMbScanLineEdge(polygon[i].first, polygon[(i + 1) % polygon.size()].first), ID,
276 createScanLinesFromLocals(scanlines, local_scanlines, w);
288void vpMbScanLine::createScanLinesFromLocals(std::vector<std::vector<vpMbScanLineSegment> > &scanlines,
289 std::vector<std::vector<vpMbScanLineSegment> > &localScanlines,
290 const unsigned int &size)
292 for (
unsigned int j = 0;
j < size; ++
j) {
293 std::vector<vpMbScanLineSegment> &scanline = localScanlines[
j];
294 sort(scanline.begin(), scanline.end(),
295 vpMbScanLineSegmentComparator());
298 for (
size_t i = 0;
i < scanline.size(); ++
i) {
299 vpMbScanLineSegment
s = scanline[
i];
306 vpMbScanLineSegment &prev = scanlines[
j].back();
315 scanlines[
j].push_back(s);
329void vpMbScanLine::drawScene(
const std::vector<std::vector<std::pair<vpPoint, unsigned int> > *> &polygons,
337 visibility_samples.clear();
339 std::vector<std::vector<vpMbScanLineSegment> > scanlinesY;
340 scanlinesY.resize(h);
341 std::vector<std::vector<vpMbScanLineSegment> > scanlinesX;
342 scanlinesX.resize(w);
344 mask.resize(h, w, 0);
349 primitive_ids.resize(h, w, -1);
351 for (
unsigned int ID = 0; ID < polygons.size(); ++ID) {
352 drawPolygonY(*(polygons[ID]), listPolyIndices[ID], scanlinesY);
353 drawPolygonX(*(polygons[ID]), listPolyIndices[ID], scanlinesX);
358 vpMbScanLineSegment last_visible;
359 for (
unsigned int y = 0;
y < scanlinesY.size(); ++
y) {
360 std::vector<vpMbScanLineSegment> &scanline = scanlinesY[
y];
361 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
363 std::vector<std::pair<double, vpMbScanLineSegment> > stack;
364 for (
size_t i = 0;
i < scanline.size(); ++
i) {
365 const vpMbScanLineSegment &
s = scanline[
i];
369 stack.push_back(std::make_pair(
s.Z1, s));
372 for (
size_t j = 0;
j < stack.size(); ++
j)
373 if (stack[j].second.ID ==
s.ID) {
374 if (j != stack.size() - 1)
375 stack[
j] = stack.back();
384 for (
size_t j = 0;
j < stack.size(); ++
j) {
385 const vpMbScanLineSegment &s0 = stack[
j].second;
386 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));
388 sort(stack.begin(), stack.end(), vpMbScanLineSegmentComparator());
390 int new_ID = stack.empty() ? -1 : stack.front().second.ID;
392 if (new_ID != last_ID ||
s.type == POINT) {
396 if (new_ID == -1 ||
s.Z1 - depthTreshold <= stack.front().first)
397 visibility_samples[
s.edge].insert(
static_cast<int>(y));
401 visibility_samples[
s.edge].insert(
static_cast<int>(y));
405 visibility_samples[
s.edge].insert(
static_cast<int>(y));
411 const unsigned int x0 = std::max<unsigned int>(
static_cast<unsigned int>(0),
static_cast<unsigned int>(std::ceil(last_visible.p)));
412 double x1 = std::min<double>(
static_cast<double>(w),
static_cast<double>(
s.p));
413 for (
unsigned int x = x0 + maskBorder;
x < x1 - maskBorder; ++
x) {
414 primitive_ids[
static_cast<unsigned int>(
y)][
static_cast<unsigned int>(x)] = last_visible.ID;
417 maskY[
static_cast<unsigned int>(
y)][
static_cast<unsigned int>(x)] = 255;
419 mask[
static_cast<unsigned int>(
y)][
static_cast<unsigned int>(x)] = 255;
424 if (!stack.empty()) {
425 last_visible = stack.front().second;
426 last_visible.p =
s.p;
434 for (
unsigned int x = 0;
x < scanlinesX.size(); ++
x) {
435 std::vector<vpMbScanLineSegment> &scanline = scanlinesX[
x];
436 sort(scanline.begin(), scanline.end(), vpMbScanLineSegmentComparator());
438 std::vector<std::pair<double, vpMbScanLineSegment> > stack;
439 for (
size_t i = 0;
i < scanline.size(); ++
i) {
440 const vpMbScanLineSegment &
s = scanline[
i];
444 stack.push_back(std::make_pair(
s.Z1, s));
447 for (
size_t j = 0;
j < stack.size(); ++
j)
448 if (stack[j].second.ID ==
s.ID) {
449 if (j != stack.size() - 1)
450 stack[
j] = stack.back();
459 for (
size_t j = 0;
j < stack.size(); ++
j) {
460 const vpMbScanLineSegment &s0 = stack[
j].second;
461 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));
463 sort(stack.begin(), stack.end(), vpMbScanLineSegmentComparator());
465 int new_ID = stack.empty() ? -1 : stack.front().second.ID;
467 if (new_ID != last_ID ||
s.type == POINT) {
471 if (new_ID == -1 ||
s.Z1 - depthTreshold <= stack.front().first)
472 visibility_samples[
s.edge].insert(
static_cast<int>(x));
476 visibility_samples[
s.edge].insert(
static_cast<int>(x));
480 visibility_samples[
s.edge].insert(
static_cast<int>(x));
485 if (maskBorder != 0 && last_ID != -1) {
486 const unsigned int y0 = std::max<unsigned int>(
static_cast<unsigned int>(0),
static_cast<unsigned int>(std::ceil(last_visible.p)));
487 double y1 = std::min<double>(
static_cast<double>(h),
static_cast<double>(
s.p));
488 for (
unsigned int y = y0 + maskBorder;
y < y1 - maskBorder; ++
y) {
491 maskX[
static_cast<unsigned int>(
y)][
static_cast<unsigned int>(x)] = 255;
496 if (!stack.empty()) {
497 last_visible = stack.front().second;
498 last_visible.p =
s.p;
505 for (
unsigned int i = 0;
i <
h;
i++)
506 for (
unsigned int j = 0;
j <
w;
j++)
507 if (maskX[i][j] == 255 && maskY[i][j] == 255)
510#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
511 if (!dispMaskDebug->isInitialised()) {
512 dispMaskDebug->init(mask, 800, 600);
517 for (
unsigned int ID = 0; ID < polygons.size(); ++ID) {
518 for (
unsigned int i = 0;
i < polygons[ID]->size();
i++) {
519 vpPoint p1 = (*(polygons[ID]))[i].first;
520 vpPoint p2 = (*(polygons[ID]))[(i + 1) % polygons[ID]->size()].first;
521 double i1 = 0, j1 = 0, i2 = 0, j2 = 0;
533 if (!dispLineDebug->isInitialised()) {
534 linedebugImg.resize(h, w, 0);
535 dispLineDebug->init(linedebugImg, 800, 100);
551void vpMbScanLine::queryLineVisibility(
const vpPoint &a,
const vpPoint &b,
552 std::vector<std::pair<vpPoint, vpPoint> > &lines,
const bool &displayResults)
555 createVectorFromPoint(a, _a, K);
556 createVectorFromPoint(b, _b, K);
558 double x0 = _a[0] / _a[2];
559 double y0 = _a[1] / _a[2];
561 double x1 = _b[0] / _b[2];
562 double y1 = _b[1] / _b[2];
565 vpMbScanLineEdge edge = makeMbScanLineEdge(a, b);
568 if (displayResults) {
569#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
570 double i1(0.0), j1(0.0), i2(0.0), j2(0.0);
581 if (!visibility_samples.count(edge))
586 double *v0(&x0), *w0(&z0);
587 double *v1(&x1), *w1(&z1);
588 unsigned int size(w);
590 if (std::fabs(y0 - y1) > std::fabs(x0 - x1))
617 if (*v0 >= size - 1 || *v1 < 0 || std::fabs(*v1 - *v0) <= std::numeric_limits<double>::epsilon())
620 const int _v0 = std::max<int>(0,
int(std::ceil(*v0)));
621 const int _v1 = std::min<int>(
static_cast<int>(size - 1),
static_cast<int>(std::ceil(*v1) - 1));
623 const std::set<int> &visible_samples = visibility_samples[edge];
627 bool b_line_started =
false;
628 for (std::set<int>::const_iterator it = visible_samples.begin(); it != visible_samples.end(); ++it) {
630 const double alpha = getAlpha(v, (*v0) * (*w0), (*w0), (*v1) * (*w1), (*w1));
632 const vpPoint p = mix(a_, b_, alpha);
635 lines.push_back(std::make_pair(line_start, line_end));
636 b_line_started =
false;
642 b_line_started =
true;
649 b_line_started =
true;
655 b_line_started =
true;
660 lines.push_back(std::make_pair(line_start, line_end));
662 if (displayResults) {
663#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI)) && defined(DEBUG_DISP)
664 double i1(0.0), j1(0.0), i2(0.0), j2(0.0);
665 for (
unsigned int i = 0;
i < lines.size();
i++) {
666 lines[
i].first.project();
667 lines[
i].second.project();
686vpMbScanLine::vpMbScanLineEdge vpMbScanLine::makeMbScanLineEdge(
const vpPoint &a,
const vpPoint &b)
691 _a[0] = std::ceil((a.
get_X() * 1e8) * 1e-6);
692 _a[1] = std::ceil((a.
get_Y() * 1e8) * 1e-6);
693 _a[2] = std::ceil((a.
get_Z() * 1e8) * 1e-6);
695 _b[0] = std::ceil((b.
get_X() * 1e8) * 1e-6);
696 _b[1] = std::ceil((b.
get_Y() * 1e8) * 1e-6);
697 _b[2] = std::ceil((b.
get_Z() * 1e8) * 1e-6);
700 for (
unsigned int i = 0;
i < 3; ++
i)
705 else if (_a[i] > _b[i])
709 return std::make_pair(_a, _b);
711 return std::make_pair(_b, _a);
725 v[0] =
p.get_X() *
K.get_px() +
K.get_u0() *
p.get_Z();
726 v[1] =
p.get_Y() *
K.get_py() +
K.get_v0() *
p.get_Z();
739double vpMbScanLine::getAlpha(
double x,
double X0,
double Z0,
double X1,
double Z1)
741 const double N =
X0 -
x * Z0;
742 const double D =
x * (Z1 - Z0) - (X1 - X0);
743 double alpha = N / D;
747 alpha = std::min<double>(1.0, alpha);
748 alpha = std::max<double>(0.0, alpha);
761double 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).
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
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)
Definition of the vpImage class member functions.
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.