Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
testFloodFill.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Test flood fill algorithm.
32 */
33
34#include <iomanip>
35
36#include <visp3/core/vpImageTools.h>
37#include <visp3/core/vpIoTools.h>
38#include <visp3/imgproc/vpImgproc.h>
39#include <visp3/io/vpImageIo.h>
40#include <visp3/io/vpParseArgv.h>
41
48// List of allowed command line options
49#define GETOPTARGS "cdi:o:h"
50
51void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user);
52bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user);
53
54/*
55 Print the program options.
56
57 \param name : Program name.
58 \param badparam : Bad parameter name.
59 \param ipath: Input image path.
60 \param opath : Output image path.
61 \param user : Username.
62 */
63void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
64{
65 fprintf(stdout, "\n\
66Test flood fill algorithm.\n\
67\n\
68SYNOPSIS\n\
69 %s [-i <input image path>] [-o <output image path>]\n\
70 [-h]\n \
71",
72 name);
73
74 fprintf(stdout, "\n\
75OPTIONS: Default\n\
76 -i <input image path> %s\n\
77 Set image input path.\n\
78 From this path read \"Klimt/Klimt.pgm\"\n\
79 image.\n\
80 Setting the VISP_INPUT_IMAGE_PATH environment\n\
81 variable produces the same behaviour than using\n\
82 this option.\n\
83\n\
84 -o <output image path> %s\n\
85 Set image output path.\n\
86 From this directory, creates the \"%s\"\n\
87 subdirectory depending on the username, where \n\
88 output result images are written.\n\
89\n\
90 -h\n\
91 Print the help.\n\n",
92 ipath.c_str(), opath.c_str(), user.c_str());
93
94 if (badparam)
95 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
96}
97
108bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user)
109{
110 const char *optarg_;
111 int c;
112 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
113
114 switch (c) {
115 case 'i':
116 ipath = optarg_;
117 break;
118 case 'o':
119 opath = optarg_;
120 break;
121 case 'h':
122 usage(argv[0], NULL, ipath, opath, user);
123 return false;
124 break;
125
126 case 'c':
127 case 'd':
128 break;
129
130 default:
131 usage(argv[0], optarg_, ipath, opath, user);
132 return false;
133 break;
134 }
135 }
136
137 if ((c == 1) || (c == -1)) {
138 // standalone param or error
139 usage(argv[0], NULL, ipath, opath, user);
140 std::cerr << "ERROR: " << std::endl;
141 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
142 return false;
143 }
144
145 return true;
146}
147
148void printImage(const vpImage<unsigned char> &I, const std::string &name)
149{
150 std::cout << "\n" << name << ":" << std::endl;
151
152 std::cout << " ";
153 for (unsigned int j = 0; j < I.getWidth(); j++) {
154 std::cout << std::setfill(' ') << std::setw(2) << j << " ";
155 }
156 std::cout << std::endl;
157
158 std::cout << std::setfill(' ') << std::setw(3) << "+";
159 for (unsigned int j = 0; j < I.getWidth(); j++) {
160 std::cout << std::setw(3) << "---";
161 }
162 std::cout << std::endl;
163
164 for (unsigned int i = 0; i < I.getHeight(); i++) {
165 std::cout << std::setfill(' ') << std::setw(2) << i << "|";
166
167 for (unsigned int j = 0; j < I.getWidth(); j++) {
168 std::cout << std::setfill(' ') << std::setw(2) << static_cast<unsigned int>(I[i][j]) << " ";
169 }
170
171 std::cout << std::endl;
172 }
173}
174
175int main(int argc, const char **argv)
176{
177#if defined(HAVE_OPENCV_IMGPROC)
178 try {
179 std::string env_ipath;
180 std::string opt_ipath;
181 std::string opt_opath;
182 std::string ipath;
183 std::string opath;
184 std::string filename;
185 std::string username;
186
187 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
188 // environment variable value
190
191 // Set the default input path
192 if (!env_ipath.empty())
193 ipath = env_ipath;
194
195// Set the default output path
196#if defined(_WIN32)
197 opt_opath = "C:/temp";
198#else
199 opt_opath = "/tmp";
200#endif
201
202 // Get the user login name
203 vpIoTools::getUserName(username);
204
205 // Read the command line options
206 if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
207 exit(EXIT_FAILURE);
208 }
209
210 // Get the option values
211 if (!opt_ipath.empty())
212 ipath = opt_ipath;
213 if (!opt_opath.empty())
214 opath = opt_opath;
215
216 // Append to the output path string, the login name of the user
217 opath = vpIoTools::createFilePath(opath, username);
218
219 // Test if the output path exist. If no try to create it
220 if (vpIoTools::checkDirectory(opath) == false) {
221 try {
222 // Create the dirname
224 } catch (...) {
225 usage(argv[0], NULL, ipath, opt_opath, username);
226 std::cerr << std::endl << "ERROR:" << std::endl;
227 std::cerr << " Cannot create " << opath << std::endl;
228 std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
229 exit(EXIT_FAILURE);
230 }
231 }
232
233 // Compare ipath and env_ipath. If they differ, we take into account
234 // the input path comming from the command line option
235 if (!opt_ipath.empty() && !env_ipath.empty()) {
236 if (ipath != env_ipath) {
237 std::cout << std::endl << "WARNING: " << std::endl;
238 std::cout << " Since -i <visp image path=" << ipath << "> "
239 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
240 << " we skip the environment variable." << std::endl;
241 }
242 }
243
244 // Test if an input path is set
245 if (opt_ipath.empty() && env_ipath.empty()) {
246 usage(argv[0], NULL, ipath, opt_opath, username);
247 std::cerr << std::endl << "ERROR:" << std::endl;
248 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
249 << " environment variable to specify the location of the " << std::endl
250 << " image path where test images are located." << std::endl
251 << std::endl;
252 exit(EXIT_FAILURE);
253 }
254
255 //
256 // Here starts really the test
257 //
258
259 unsigned char image_data[8 * 8] = {1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
260 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1,
261 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0};
262 vpImage<unsigned char> I_test_flood_fill_4_connexity(image_data, 8, 8, true);
263 vpImage<unsigned char> I_test_flood_fill_8_connexity = I_test_flood_fill_4_connexity;
264 printImage(I_test_flood_fill_4_connexity, "Test image data");
265
266 unsigned char image_data_check_4_connexity[8 * 8] = {
267 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
268 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0};
269 vpImage<unsigned char> I_check_4_connexity(image_data_check_4_connexity, 8, 8, true);
270
271 unsigned char image_data_check_8_connexity[8 * 8] = {
272 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
273 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0};
274 vpImage<unsigned char> I_check_8_connexity(image_data_check_8_connexity, 8, 8, true);
275
276 // Test flood fill on test data 4-connexity
277 vp::floodFill(I_test_flood_fill_4_connexity, vpImagePoint(2, 2), 0, 1, vpImageMorphology::CONNEXITY_4);
278 printImage(I_test_flood_fill_4_connexity, "I_test_flood_fill_4_connexity");
279
280 if (I_test_flood_fill_4_connexity != I_check_4_connexity) {
281 throw vpException(vpException::fatalError, "Problem with vp::floodFill() and 4-connexity!");
282 }
283 std::cout << "\n(I_test_flood_fill_4_connexity == I_check_4_connexity)? "
284 << (I_test_flood_fill_4_connexity == I_check_4_connexity) << std::endl;
285
286 // Test flood fill on test data 8-connexity
287 vp::floodFill(I_test_flood_fill_8_connexity, vpImagePoint(2, 2), 0, 1, vpImageMorphology::CONNEXITY_8);
288 printImage(I_test_flood_fill_8_connexity, "I_test_flood_fill_8_connexity");
289
290 if (I_test_flood_fill_8_connexity != I_check_8_connexity) {
291 throw vpException(vpException::fatalError, "Problem with vp::floodFill() and 8-connexity!");
292 }
293 std::cout << "\n(I_test_flood_fill_8_connexity == I_check_8_connexity)? "
294 << (I_test_flood_fill_8_connexity == I_check_8_connexity) << std::endl;
295
296 // Read Klimt.ppm
297 filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
299 vpImageIo::read(I_klimt, filename);
300 std::cout << "\nRead image: " << filename << " (" << I_klimt.getWidth() << "x" << I_klimt.getHeight() << ")"
301 << std::endl
302 << std::endl;
303 vpImageTools::binarise(I_klimt, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)255,
304 (unsigned char)255);
305
306 int seed_x = 0;
307 int seed_y = 0;
308
309 vpImage<unsigned char> I_klimt_flood_fill_4_connexity = I_klimt;
310 double t = vpTime::measureTimeMs();
311 vp::floodFill(I_klimt_flood_fill_4_connexity, vpImagePoint(seed_y, seed_x), 0, 255, vpImageMorphology::CONNEXITY_4);
312 t = vpTime::measureTimeMs() - t;
313 std::cout << "Flood fill on Klimt image (4-connexity): " << t << " ms" << std::endl;
314
315 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_4_connexity.pgm");
316 vpImageIo::write(I_klimt_flood_fill_4_connexity, filename);
317
318 vpImage<unsigned char> I_klimt_flood_fill_8_connexity = I_klimt;
320 vp::floodFill(I_klimt_flood_fill_8_connexity, vpImagePoint(seed_y, seed_x), 0, 255, vpImageMorphology::CONNEXITY_8);
321 t = vpTime::measureTimeMs() - t;
322 std::cout << "Flood fill on Klimt image (8-connexity): " << t << " ms" << std::endl;
323 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_8_connexity.pgm");
324 vpImageIo::write(I_klimt_flood_fill_8_connexity, filename);
325
326 cv::Mat matImg_klimt_4_connexity, matImg_klimt_8_connexity;
327 vpImageConvert::convert(I_klimt, matImg_klimt_4_connexity);
328 vpImageConvert::convert(I_klimt, matImg_klimt_8_connexity);
329
330 // 4-connexity
332 cv::floodFill(matImg_klimt_4_connexity, cv::Point(seed_x, seed_y), cv::Scalar(255), 0, cv::Scalar(), cv::Scalar(),
333 4);
334 t = vpTime::measureTimeMs() - t;
335 std::cout << "OpenCV flood fill on Klimt image (4-connexity): " << t << " ms" << std::endl;
336
337 vpImage<unsigned char> I_klimt_flood_fill_4_connexity_check;
338 vpImageConvert::convert(matImg_klimt_4_connexity, I_klimt_flood_fill_4_connexity_check);
339
340 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_4_connexity_opencv.pgm");
341 vpImageIo::write(I_klimt_flood_fill_4_connexity_check, filename);
342
343 // 8-connexity
345 cv::floodFill(matImg_klimt_8_connexity, cv::Point(seed_x, seed_y), cv::Scalar(255), 0, cv::Scalar(), cv::Scalar(),
346 8);
347 t = vpTime::measureTimeMs() - t;
348 std::cout << "OpenCV flood fill on Klimt image (8-connexity): " << t << " ms" << std::endl;
349
350 vpImage<unsigned char> I_klimt_flood_fill_8_connexity_check;
351 vpImageConvert::convert(matImg_klimt_8_connexity, I_klimt_flood_fill_8_connexity_check);
352
353 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_8_connexity_opencv.pgm");
354 vpImageIo::write(I_klimt_flood_fill_8_connexity_check, filename);
355
356 // Check
357 std::cout << "\n(I_klimt_flood_fill_4_connexity == "
358 "I_klimt_flood_fill_4_connexity_check)? "
359 << (I_klimt_flood_fill_4_connexity == I_klimt_flood_fill_4_connexity_check) << std::endl;
360 std::cout << "(I_klimt_flood_fill_8_connexity == "
361 "I_klimt_flood_fill_8_connexity_check)? "
362 << (I_klimt_flood_fill_8_connexity == I_klimt_flood_fill_8_connexity_check) << std::endl;
363
364 if (I_klimt_flood_fill_4_connexity != I_klimt_flood_fill_4_connexity_check) {
365 throw vpException(vpException::fatalError, "(I_klimt_flood_fill_4_connexity != "
366 "I_klimt_flood_fill_4_connexity_check)");
367 }
368 if (I_klimt_flood_fill_8_connexity != I_klimt_flood_fill_8_connexity_check) {
369 throw vpException(vpException::fatalError, "(I_klimt_flood_fill_8_connexity != "
370 "I_klimt_flood_fill_8_connexity_check)");
371 }
372
373 std::cout << "\nTest flood fill is ok!" << std::endl;
374 return EXIT_SUCCESS;
375 } catch (const vpException &e) {
376 std::cerr << "Catch an exception: " << e.what() << std::endl;
377 return EXIT_FAILURE;
378 }
379#else
380 (void) argc;
381 (void) argv;
382 std::cout << "Install OpenCV imgproc module required by this test" << std::endl;
383 return EXIT_SUCCESS;
384#endif
385}
error that can be emitted by ViSP classes.
Definition vpException.h:59
@ fatalError
Fatal error.
Definition vpException.h:84
const char * what() const
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, bool useLUT=true)
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:184
static std::string getViSPImagesDataPath()
static bool checkDirectory(const std::string &dirname)
static std::string getUserName()
static std::string createFilePath(const std::string &parent, const std::string &child)
static void makeDirectory(const std::string &dirname)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT void floodFill(vpImage< unsigned char > &I, const vpImagePoint &seedPoint, const unsigned char oldValue, const unsigned char newValue, const vpImageMorphology::vpConnexityType &connexity=vpImageMorphology::CONNEXITY_4)
VISP_EXPORT double measureTimeMs()