Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
tutorial-flood-fill.cpp
1
2
3#include <cstdlib>
4#include <iostream>
5#include <visp3/core/vpConfig.h>
6#include <visp3/core/vpImage.h>
7#include <visp3/gui/vpDisplayFactory.h>
8
9#if defined(VISP_HAVE_MODULE_IMGPROC) && defined(VISP_HAVE_DISPLAY)
11#include <visp3/imgproc/vpImgproc.h>
13
14#ifdef ENABLE_VISP_NAMESPACE
15using namespace VISP_NAMESPACE_NAME;
16#endif
17
18namespace
19{
21vpImagePoint switchToOctantZeroFrom(const int octant, const vpImagePoint &imPt)
22{
23 vpImagePoint imPt_switched = imPt;
24
25 switch (octant) {
26 case 0: // return (x, y)
27 imPt_switched.set_uv(imPt.get_u(), imPt.get_v());
28 break;
29
30 case 1: // return (y, x)
31 imPt_switched.set_uv(imPt.get_v(), imPt.get_u());
32 break;
33
34 case 2: // return (y, -x)
35 imPt_switched.set_uv(imPt.get_v(), -imPt.get_u());
36 break;
37
38 case 3: // return (-x, y)
39 imPt_switched.set_uv(-imPt.get_u(), imPt.get_v());
40 break;
41
42 case 4: // return (-x, -y)
43 imPt_switched.set_uv(-imPt.get_u(), -imPt.get_v());
44 break;
45
46 case 5: // return (-y, -x)
47 imPt_switched.set_uv(-imPt.get_v(), -imPt.get_u());
48 break;
49
50 case 6: // return (-y, x)
51 imPt_switched.set_uv(-imPt.get_v(), imPt.get_u());
52 break;
53
54 case 7: // return (x, -y)
55 imPt_switched.set_uv(imPt.get_u(), -imPt.get_v());
56 break;
57
58 default:
59 break;
60 }
61
62 return imPt_switched;
63}
64
65vpImagePoint switchFromOctantZeroTo(const int octant, const vpImagePoint &imPt)
66{
67 vpImagePoint imPt_switched = imPt;
68
69 switch (octant) {
70 case 0: // return (x, y)
71 imPt_switched.set_uv(imPt.get_u(), imPt.get_v());
72 break;
73
74 case 1: // return (y, x)
75 imPt_switched.set_uv(imPt.get_v(), imPt.get_u());
76 break;
77
78 case 2: // return (-y, x)
79 imPt_switched.set_uv(-imPt.get_v(), imPt.get_u());
80 break;
81
82 case 3: // return (-x, y)
83 imPt_switched.set_uv(-imPt.get_u(), imPt.get_v());
84 break;
85
86 case 4: // return (-x, -y)
87 imPt_switched.set_uv(-imPt.get_u(), -imPt.get_v());
88 break;
89
90 case 5: // return (-y, -x)
91 imPt_switched.set_uv(-imPt.get_v(), -imPt.get_u());
92 break;
93
94 case 6: // return (y, -x)
95 imPt_switched.set_uv(imPt.get_v(), -imPt.get_u());
96 break;
97
98 case 7: // return (x, -y)
99 imPt_switched.set_uv(imPt.get_u(), -imPt.get_v());
100 break;
101
102 default:
103 break;
104 }
105
106 return imPt_switched;
107}
108
109int getOctant(const vpImagePoint &imPt1, const vpImagePoint &imPt2)
110{
111 double dx = imPt2.get_u() - imPt1.get_u();
112 double dy = imPt2.get_v() - imPt1.get_v();
113
114 if (dx >= 0 && dy >= 0) {
115 if (dy >= dx) {
116 return 1;
117 }
118 else {
119 return 0;
120 }
121 }
122 else if (dx < 0 && dy >= 0) {
123 if (-dx >= dy) {
124 return 3;
125 }
126 else {
127 return 2;
128 }
129 }
130 else if (dx < 0 && dy < 0) {
131 if (dy <= dx) {
132 return 5;
133 }
134 else {
135 return 4;
136 }
137 }
138 else {
139 if (dx >= -dy) {
140 return 7;
141 }
142 else {
143 return 6;
144 }
145 }
146}
147
148void drawLine(vpImage<unsigned char> &I, const unsigned char value, const vpImagePoint &imPt1_,
149 const vpImagePoint &imPt2_)
150{
151 vpImagePoint imPt1(static_cast<int>(imPt1_.get_v()), static_cast<int>(imPt1_.get_u()));
152 vpImagePoint imPt2(static_cast<int>(imPt2_.get_v()), static_cast<int>(imPt2_.get_u()));
153
154 int octant = getOctant(imPt1, imPt2);
155 imPt1 = switchToOctantZeroFrom(octant, imPt1);
156 imPt2 = switchToOctantZeroFrom(octant, imPt2);
157
158 double dx = imPt2.get_u() - imPt1.get_u();
159 double dy = imPt2.get_v() - imPt1.get_v();
160 double D = 2 * dy - dx;
161 double y = imPt1.get_v();
162
163 for (int x = static_cast<int>(imPt1.get_u()); x <= static_cast<int>(imPt2.get_u()); x++) {
164 vpImagePoint currentPt(y, x);
165 currentPt = switchFromOctantZeroTo(octant, currentPt);
166
167 unsigned int i = std::min<unsigned int>(I.getHeight() - 1, static_cast<unsigned int>(std::max<double>(0.0, currentPt.get_i())));
168 unsigned int j = std::min<unsigned int>(I.getWidth() - 1, static_cast<unsigned int>(std::max<double>(0.0, currentPt.get_j())));
169 I[i][j] = value;
170
171 if (D >= 0) {
172 y++;
173 D -= dx;
174 }
175
176 D += dy;
177 }
178}
180} // namespace
181
182#endif
183
184int main()
185{
187#if defined(VISP_HAVE_MODULE_IMGPROC) && defined(VISP_HAVE_DISPLAY)
189
191 vpImage<vpRGBa> I(480, 640, vpRGBa());
193
194#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
195 std::shared_ptr<vpDisplay> display = vpDisplayFactory::createDisplay();
196#else
198#endif
199 display->init(I, 0, 0, "Paint");
200
202 std::vector<vpPolygon> polygons;
203 for (int i = 0; i < 3; i++) {
205 std::stringstream ss;
206 ss << "Left click to draw polygon " << i + 1 << "/3"
207 << ", right click to close the shape.";
208 vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
210
211 vpPolygon polygon;
212 polygon.initClick(I);
213 polygons.push_back(polygon);
214
218
219 // Update the lines draw internally in the current image
221 }
223
225 vpImage<unsigned char> mask(I.getHeight(), I.getWidth(), 0);
226 for (size_t i = 0; i < polygons.size(); i++) {
227 if (polygons[i].getCorners().size() <= 1)
228 continue;
229
230 for (size_t j = 0; j < polygons[i].getCorners().size() - 1; j++)
231 drawLine(mask, 255, polygons[i].getCorners()[j], polygons[i].getCorners()[j + 1]);
232
233 drawLine(mask, 255, polygons[i].getCorners().front(), polygons[i].getCorners().back());
234 }
236
237 bool quit = false;
238 while (!quit) {
240 vpDisplay::displayText(I, 20, 20,
241 "Left click on a pixel location to fill the "
242 "shape, right click to quit.",
245
247 vpImagePoint ip;
249 if (vpDisplay::getClick(I, ip, button, false))
251 {
252 switch (button) {
257
259 for (unsigned int cpt = 0; cpt < mask.getSize(); cpt++) {
260 if (mask.bitmap[cpt])
261 I.bitmap[cpt] = vpColor::red;
262 }
264 break;
265
267 quit = true;
268 break;
269
270 default:
271 break;
272 }
273 }
274 }
275
276#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11) && defined(VISP_HAVE_DISPLAY)
277 if (display != nullptr) {
278 delete display;
279 }
280#endif
281#endif
282
283 return EXIT_SUCCESS;
284}
static const vpColor red
Definition vpColor.h:198
Class that defines generic functionalities for display.
Definition vpDisplay.h:171
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)
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 ...
double get_u() const
void set_uv(double u, double v)
double get_v() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
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)
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)
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.