Visual Servoing Platform  version 3.6.1 under development (2024-11-24)
tutorial-flood-fill.cpp
1 
3 #include <cstdlib>
4 #include <iostream>
5 #include <visp3/core/vpConfig.h>
6 #include <visp3/core/vpImage.h>
7 #include <visp3/gui/vpDisplayGDI.h>
8 #include <visp3/gui/vpDisplayOpenCV.h>
9 #include <visp3/gui/vpDisplayX.h>
10 
11 #if defined(VISP_HAVE_MODULE_IMGPROC) && (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
13 #include <visp3/imgproc/vpImgproc.h>
15 
16 #ifdef ENABLE_VISP_NAMESPACE
17 using namespace VISP_NAMESPACE_NAME;
18 #endif
19 
20 namespace
21 {
23 vpImagePoint switchToOctantZeroFrom(const int octant, const vpImagePoint &imPt)
24 {
25  vpImagePoint imPt_switched = imPt;
26 
27  switch (octant) {
28  case 0: // return (x, y)
29  imPt_switched.set_uv(imPt.get_u(), imPt.get_v());
30  break;
31 
32  case 1: // return (y, x)
33  imPt_switched.set_uv(imPt.get_v(), imPt.get_u());
34  break;
35 
36  case 2: // return (y, -x)
37  imPt_switched.set_uv(imPt.get_v(), -imPt.get_u());
38  break;
39 
40  case 3: // return (-x, y)
41  imPt_switched.set_uv(-imPt.get_u(), imPt.get_v());
42  break;
43 
44  case 4: // return (-x, -y)
45  imPt_switched.set_uv(-imPt.get_u(), -imPt.get_v());
46  break;
47 
48  case 5: // return (-y, -x)
49  imPt_switched.set_uv(-imPt.get_v(), -imPt.get_u());
50  break;
51 
52  case 6: // return (-y, x)
53  imPt_switched.set_uv(-imPt.get_v(), imPt.get_u());
54  break;
55 
56  case 7: // return (x, -y)
57  imPt_switched.set_uv(imPt.get_u(), -imPt.get_v());
58  break;
59 
60  default:
61  break;
62  }
63 
64  return imPt_switched;
65 }
66 
67 vpImagePoint switchFromOctantZeroTo(const int octant, const vpImagePoint &imPt)
68 {
69  vpImagePoint imPt_switched = imPt;
70 
71  switch (octant) {
72  case 0: // return (x, y)
73  imPt_switched.set_uv(imPt.get_u(), imPt.get_v());
74  break;
75 
76  case 1: // return (y, x)
77  imPt_switched.set_uv(imPt.get_v(), imPt.get_u());
78  break;
79 
80  case 2: // return (-y, x)
81  imPt_switched.set_uv(-imPt.get_v(), imPt.get_u());
82  break;
83 
84  case 3: // return (-x, y)
85  imPt_switched.set_uv(-imPt.get_u(), imPt.get_v());
86  break;
87 
88  case 4: // return (-x, -y)
89  imPt_switched.set_uv(-imPt.get_u(), -imPt.get_v());
90  break;
91 
92  case 5: // return (-y, -x)
93  imPt_switched.set_uv(-imPt.get_v(), -imPt.get_u());
94  break;
95 
96  case 6: // return (y, -x)
97  imPt_switched.set_uv(imPt.get_v(), -imPt.get_u());
98  break;
99 
100  case 7: // return (x, -y)
101  imPt_switched.set_uv(imPt.get_u(), -imPt.get_v());
102  break;
103 
104  default:
105  break;
106  }
107 
108  return imPt_switched;
109 }
110 
111 int getOctant(const vpImagePoint &imPt1, const vpImagePoint &imPt2)
112 {
113  double dx = imPt2.get_u() - imPt1.get_u();
114  double dy = imPt2.get_v() - imPt1.get_v();
115 
116  if (dx >= 0 && dy >= 0) {
117  if (dy >= dx) {
118  return 1;
119  }
120  else {
121  return 0;
122  }
123  }
124  else if (dx < 0 && dy >= 0) {
125  if (-dx >= dy) {
126  return 3;
127  }
128  else {
129  return 2;
130  }
131  }
132  else if (dx < 0 && dy < 0) {
133  if (dy <= dx) {
134  return 5;
135  }
136  else {
137  return 4;
138  }
139  }
140  else {
141  if (dx >= -dy) {
142  return 7;
143  }
144  else {
145  return 6;
146  }
147  }
148 }
149 
150 void drawLine(vpImage<unsigned char> &I, const unsigned char value, const vpImagePoint &imPt1_,
151  const vpImagePoint &imPt2_)
152 {
153  vpImagePoint imPt1((int)imPt1_.get_v(), (int)imPt1_.get_u());
154  vpImagePoint imPt2((int)imPt2_.get_v(), (int)imPt2_.get_u());
155 
156  int octant = getOctant(imPt1, imPt2);
157  imPt1 = switchToOctantZeroFrom(octant, imPt1);
158  imPt2 = switchToOctantZeroFrom(octant, imPt2);
159 
160  double dx = imPt2.get_u() - imPt1.get_u();
161  double dy = imPt2.get_v() - imPt1.get_v();
162  double D = 2 * dy - dx;
163  double y = imPt1.get_v();
164 
165  for (int x = (int)imPt1.get_u(); x <= (int)imPt2.get_u(); x++) {
166  vpImagePoint currentPt(y, x);
167  currentPt = switchFromOctantZeroTo(octant, currentPt);
168 
169  unsigned int i = std::min<unsigned int>(I.getHeight() - 1, (unsigned int)std::max<double>(0.0, currentPt.get_i()));
170  unsigned int j = std::min<unsigned int>(I.getWidth() - 1, (unsigned int)std::max<double>(0.0, currentPt.get_j()));
171  I[i][j] = value;
172 
173  if (D >= 0) {
174  y++;
175  D -= dx;
176  }
177 
178  D += dy;
179  }
180 }
182 } // namespace
183 
184 #endif
185 
186 int main()
187 {
189 #if defined(VISP_HAVE_MODULE_IMGPROC) && (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV))
191 
193  vpImage<vpRGBa> I(480, 640, vpRGBa());
195 
196 #ifdef VISP_HAVE_X11
197  vpDisplayX d;
198 #elif defined(VISP_HAVE_GDI)
199  vpDisplayGDI d;
200 #elif defined(HAVE_OPENCV_HIGHGUI)
201  vpDisplayOpenCV d;
202 #endif
203  d.init(I, 0, 0, "Paint");
204 
206  std::vector<vpPolygon> polygons;
207  for (int i = 0; i < 3; i++) {
209  std::stringstream ss;
210  ss << "Left click to draw polygon " << i + 1 << "/3"
211  << ", right click to close the shape.";
212  vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
213  vpDisplay::flush(I);
214 
215  vpPolygon polygon;
216  polygon.initClick(I);
217  polygons.push_back(polygon);
218 
220  vpDisplay::displayLine(I, polygon.getCorners(), true, vpColor::red);
221  vpDisplay::flush(I);
222 
223  // Update the lines draw internally in the current image
224  vpDisplay::getImage(I, I);
225  }
227 
229  vpImage<unsigned char> mask(I.getHeight(), I.getWidth(), 0);
230  for (size_t i = 0; i < polygons.size(); i++) {
231  if (polygons[i].getCorners().size() <= 1)
232  continue;
233 
234  for (size_t j = 0; j < polygons[i].getCorners().size() - 1; j++)
235  drawLine(mask, 255, polygons[i].getCorners()[j], polygons[i].getCorners()[j + 1]);
236 
237  drawLine(mask, 255, polygons[i].getCorners().front(), polygons[i].getCorners().back());
238  }
240 
241  bool quit = false;
242  while (!quit) {
244  vpDisplay::displayText(I, 20, 20,
245  "Left click on a pixel location to fill the "
246  "shape, right click to quit.",
247  vpColor::red);
248  vpDisplay::flush(I);
249 
251  vpImagePoint ip;
253  if (vpDisplay::getClick(I, ip, button, false))
255  {
256  switch (button) {
261 
263  for (unsigned int cpt = 0; cpt < mask.getSize(); cpt++) {
264  if (mask.bitmap[cpt])
265  I.bitmap[cpt] = vpColor::red;
266  }
268  break;
269 
271  quit = true;
272  break;
273 
274  default:
275  break;
276  }
277  }
278  }
279 #endif
280 
281  return EXIT_SUCCESS;
282 }
static const vpColor red
Definition: vpColor.h:217
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:130
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="") VP_OVERRIDE
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
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 getImage(const vpImage< unsigned char > &Is, vpImage< vpRGBa > &Id)
Definition: vpDisplay.cpp:140
static void flush(const vpImage< unsigned char > &I)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
double get_u() const
Definition: vpImagePoint.h:136
void set_uv(double u, double v)
Definition: vpImagePoint.h:357
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:242
Type * bitmap
points toward the bitmap
Definition: vpImage.h:135
unsigned int getHeight() const
Definition: vpImage.h:181
Defines a generic 2D polygon.
Definition: vpPolygon.h:103
const std::vector< vpImagePoint > & getCorners() const
Definition: vpPolygon.h:140
void initClick(const vpImage< unsigned char > &I, unsigned int size=5, const vpColor &color=vpColor::red, unsigned int thickness=1)
Definition: vpPolygon.cpp:265
Definition: vpRGBa.h:65
VISP_EXPORT void floodFill(VISP_NAMESPACE_ADDRESSING vpImage< unsigned char > &I, const VISP_NAMESPACE_ADDRESSING vpImagePoint &seedPoint, const unsigned char oldValue, const unsigned char newValue, const VISP_NAMESPACE_ADDRESSING vpImageMorphology::vpConnexityType &connexity=VISP_NAMESPACE_ADDRESSING vpImageMorphology::CONNEXITY_4)