Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testFloodFill.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 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
39
40#include <iomanip>
41
42#include <visp3/core/vpImageTools.h>
43#include <visp3/core/vpIoTools.h>
44#include <visp3/imgproc/vpImgproc.h>
45#include <visp3/io/vpImageIo.h>
46#include <visp3/io/vpParseArgv.h>
47
48// List of allowed command line options
49#define GETOPTARGS "cdi:o:h"
50
51#ifdef ENABLE_VISP_NAMESPACE
52using namespace VISP_NAMESPACE_NAME;
53#endif
54
55void usage(const char *name, const char *badparam, const std::string &ipath, const std::string &opath, const std::string &user);
56bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user);
57
58/*
59 Print the program options.
60
61 \param name : Program name.
62 \param badparam : Bad parameter name.
63 \param ipath : Input image path.
64 \param opath : Output image path.
65 \param user : Username.
66 */
67void usage(const char *name, const char *badparam, const std::string &ipath, const std::string &opath, const std::string &user)
68{
69 fprintf(stdout, "\n\
70Test flood fill algorithm.\n\
71\n\
72SYNOPSIS\n\
73 %s [-i <input image path>] [-o <output image path>]\n\
74 [-h]\n \
75",
76name);
77
78 fprintf(stdout, "\n\
79OPTIONS: Default\n\
80 -i <input image path> %s\n\
81 Set image input path.\n\
82 From this path read \"Klimt/Klimt.pgm\"\n\
83 image.\n\
84 Setting the VISP_INPUT_IMAGE_PATH environment\n\
85 variable produces the same behaviour than using\n\
86 this option.\n\
87\n\
88 -o <output image path> %s\n\
89 Set image output path.\n\
90 From this directory, creates the \"%s\"\n\
91 subdirectory depending on the username, where \n\
92 output result images are written.\n\
93\n\
94 -h\n\
95 Print the help.\n\n",
96 ipath.c_str(), opath.c_str(), user.c_str());
97
98 if (badparam)
99 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
100}
101
112bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user)
113{
114 const char *optarg_;
115 int c;
116 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
117
118 switch (c) {
119 case 'i':
120 ipath = optarg_;
121 break;
122 case 'o':
123 opath = optarg_;
124 break;
125 case 'h':
126 usage(argv[0], nullptr, ipath, opath, user);
127 return false;
128
129 case 'c':
130 case 'd':
131 break;
132
133 default:
134 usage(argv[0], optarg_, ipath, opath, user);
135 return false;
136 }
137 }
138
139 if ((c == 1) || (c == -1)) {
140 // standalone param or error
141 usage(argv[0], nullptr, ipath, opath, user);
142 std::cerr << "ERROR: " << std::endl;
143 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
144 return false;
145 }
146
147 return true;
148}
149
150void printImage(const vpImage<unsigned char> &I, const std::string &name)
151{
152 std::cout << "\n" << name << ":" << std::endl;
153
154 std::cout << " ";
155 for (unsigned int j = 0; j < I.getWidth(); j++) {
156 std::cout << std::setfill(' ') << std::setw(2) << j << " ";
157 }
158 std::cout << std::endl;
159
160 std::cout << std::setfill(' ') << std::setw(3) << "+";
161 for (unsigned int j = 0; j < I.getWidth(); j++) {
162 std::cout << std::setw(3) << "---";
163 }
164 std::cout << std::endl;
165
166 for (unsigned int i = 0; i < I.getHeight(); i++) {
167 std::cout << std::setfill(' ') << std::setw(2) << i << "|";
168
169 for (unsigned int j = 0; j < I.getWidth(); j++) {
170 std::cout << std::setfill(' ') << std::setw(2) << static_cast<unsigned int>(I[i][j]) << " ";
171 }
172
173 std::cout << std::endl;
174 }
175}
176
177int main(int argc, const char **argv)
178{
179#if defined(HAVE_OPENCV_IMGPROC)
180 try {
181 std::string env_ipath;
182 std::string opt_ipath;
183 std::string opt_opath;
184 std::string ipath;
185 std::string opath;
186 std::string filename;
187 std::string username;
188
189 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
190 // environment variable value
192
193 // Set the default input path
194 if (!env_ipath.empty())
195 ipath = env_ipath;
196
197// Set the default output path
198#if defined(_WIN32)
199 opt_opath = "C:/temp";
200#else
201 opt_opath = "/tmp";
202#endif
203
204 // Get the user login name
205 vpIoTools::getUserName(username);
206
207 // Read the command line options
208 if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
209 exit(EXIT_FAILURE);
210 }
211
212 // Get the option values
213 if (!opt_ipath.empty())
214 ipath = opt_ipath;
215 if (!opt_opath.empty())
216 opath = opt_opath;
217
218 // Append to the output path string, the login name of the user
219 opath = vpIoTools::createFilePath(opath, username);
220
221 // Test if the output path exist. If no try to create it
222 if (vpIoTools::checkDirectory(opath) == false) {
223 try {
224 // Create the dirname
226 }
227 catch (...) {
228 usage(argv[0], nullptr, ipath, opt_opath, username);
229 std::cerr << std::endl << "ERROR:" << std::endl;
230 std::cerr << " Cannot create " << opath << std::endl;
231 std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
232 exit(EXIT_FAILURE);
233 }
234 }
235
236 // Compare ipath and env_ipath. If they differ, we take into account
237 // the input path coming from the command line option
238 if (!opt_ipath.empty() && !env_ipath.empty()) {
239 if (ipath != env_ipath) {
240 std::cout << std::endl << "WARNING: " << std::endl;
241 std::cout << " Since -i <visp image path=" << ipath << "> "
242 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
243 << " we skip the environment variable." << std::endl;
244 }
245 }
246
247 // Test if an input path is set
248 if (opt_ipath.empty() && env_ipath.empty()) {
249 usage(argv[0], nullptr, ipath, opt_opath, username);
250 std::cerr << std::endl << "ERROR:" << std::endl;
251 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
252 << " environment variable to specify the location of the " << std::endl
253 << " image path where test images are located." << std::endl
254 << std::endl;
255 exit(EXIT_FAILURE);
256 }
257
258 //
259 // Here starts really the test
260 //
261
262 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,
263 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1,
264 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0 };
265 vpImage<unsigned char> I_test_flood_fill_4_connexity(image_data, 8, 8, true);
266 vpImage<unsigned char> I_test_flood_fill_8_connexity = I_test_flood_fill_4_connexity;
267 printImage(I_test_flood_fill_4_connexity, "Test image data");
268
269 unsigned char image_data_check_4_connexity[8 * 8] = {
270 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,
271 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 };
272 vpImage<unsigned char> I_check_4_connexity(image_data_check_4_connexity, 8, 8, true);
273
274 unsigned char image_data_check_8_connexity[8 * 8] = {
275 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,
276 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 };
277 vpImage<unsigned char> I_check_8_connexity(image_data_check_8_connexity, 8, 8, true);
278
279 // Test flood fill on test data 4-connexity
280 VISP_NAMESPACE_NAME::floodFill(I_test_flood_fill_4_connexity, vpImagePoint(2, 2), 0, 1, vpImageMorphology::CONNEXITY_4);
281 printImage(I_test_flood_fill_4_connexity, "I_test_flood_fill_4_connexity");
282
283 if (I_test_flood_fill_4_connexity != I_check_4_connexity) {
284 throw vpException(vpException::fatalError, "Problem with VISP_NAMESPACE_NAME::floodFill() and 4-connexity!");
285 }
286 std::cout << "\n(I_test_flood_fill_4_connexity == I_check_4_connexity)? "
287 << (I_test_flood_fill_4_connexity == I_check_4_connexity) << std::endl;
288
289// Test flood fill on test data 8-connexity
290 VISP_NAMESPACE_NAME::floodFill(I_test_flood_fill_8_connexity, vpImagePoint(2, 2), 0, 1, vpImageMorphology::CONNEXITY_8);
291 printImage(I_test_flood_fill_8_connexity, "I_test_flood_fill_8_connexity");
292
293 if (I_test_flood_fill_8_connexity != I_check_8_connexity) {
294 throw vpException(vpException::fatalError, "Problem with VISP_NAMESPACE_NAME::floodFill() and 8-connexity!");
295 }
296 std::cout << "\n(I_test_flood_fill_8_connexity == I_check_8_connexity)? "
297 << (I_test_flood_fill_8_connexity == I_check_8_connexity) << std::endl;
298
299// Read Klimt.ppm
300 filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
302 vpImageIo::read(I_klimt, filename);
303 std::cout << "\nRead image: " << filename << " (" << I_klimt.getWidth() << "x" << I_klimt.getHeight() << ")"
304 << std::endl
305 << std::endl;
306 vpImageTools::binarise(I_klimt, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)255,
307 (unsigned char)255);
308
309 int seed_x = 0;
310 int seed_y = 0;
311
312 vpImage<unsigned char> I_klimt_flood_fill_4_connexity = I_klimt;
313 double t = vpTime::measureTimeMs();
314 VISP_NAMESPACE_NAME::floodFill(I_klimt_flood_fill_4_connexity, vpImagePoint(seed_y, seed_x), 0, 255, vpImageMorphology::CONNEXITY_4);
316 std::cout << "Flood fill on Klimt image (4-connexity): " << t << " ms" << std::endl;
317
318 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_4_connexity.pgm");
319 vpImageIo::write(I_klimt_flood_fill_4_connexity, filename);
320
321 vpImage<unsigned char> I_klimt_flood_fill_8_connexity = I_klimt;
323 VISP_NAMESPACE_NAME::floodFill(I_klimt_flood_fill_8_connexity, vpImagePoint(seed_y, seed_x), 0, 255, vpImageMorphology::CONNEXITY_8);
325 std::cout << "Flood fill on Klimt image (8-connexity): " << t << " ms" << std::endl;
326 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_8_connexity.pgm");
327 vpImageIo::write(I_klimt_flood_fill_8_connexity, filename);
328
329 cv::Mat matImg_klimt_4_connexity, matImg_klimt_8_connexity;
330 vpImageConvert::convert(I_klimt, matImg_klimt_4_connexity);
331 vpImageConvert::convert(I_klimt, matImg_klimt_8_connexity);
332
333 // 4-connexity
335 cv::floodFill(matImg_klimt_4_connexity, cv::Point(seed_x, seed_y), cv::Scalar(255), 0, cv::Scalar(), cv::Scalar(),
336 4);
338 std::cout << "OpenCV flood fill on Klimt image (4-connexity): " << t << " ms" << std::endl;
339
340 vpImage<unsigned char> I_klimt_flood_fill_4_connexity_check;
341 vpImageConvert::convert(matImg_klimt_4_connexity, I_klimt_flood_fill_4_connexity_check);
342
343 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_4_connexity_opencv.pgm");
344 vpImageIo::write(I_klimt_flood_fill_4_connexity_check, filename);
345
346 // 8-connexity
348 cv::floodFill(matImg_klimt_8_connexity, cv::Point(seed_x, seed_y), cv::Scalar(255), 0, cv::Scalar(), cv::Scalar(),
349 8);
351 std::cout << "OpenCV flood fill on Klimt image (8-connexity): " << t << " ms" << std::endl;
352
353 vpImage<unsigned char> I_klimt_flood_fill_8_connexity_check;
354 vpImageConvert::convert(matImg_klimt_8_connexity, I_klimt_flood_fill_8_connexity_check);
355
356 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_8_connexity_opencv.pgm");
357 vpImageIo::write(I_klimt_flood_fill_8_connexity_check, filename);
358
359 // Check
360 std::cout << "\n(I_klimt_flood_fill_4_connexity == "
361 "I_klimt_flood_fill_4_connexity_check)? "
362 << (I_klimt_flood_fill_4_connexity == I_klimt_flood_fill_4_connexity_check) << std::endl;
363 std::cout << "(I_klimt_flood_fill_8_connexity == "
364 "I_klimt_flood_fill_8_connexity_check)? "
365 << (I_klimt_flood_fill_8_connexity == I_klimt_flood_fill_8_connexity_check) << std::endl;
366
367 if (I_klimt_flood_fill_4_connexity != I_klimt_flood_fill_4_connexity_check) {
368 throw vpException(vpException::fatalError, "(I_klimt_flood_fill_4_connexity != "
369 "I_klimt_flood_fill_4_connexity_check)");
370 }
371 if (I_klimt_flood_fill_8_connexity != I_klimt_flood_fill_8_connexity_check) {
372 throw vpException(vpException::fatalError, "(I_klimt_flood_fill_8_connexity != "
373 "I_klimt_flood_fill_8_connexity_check)");
374 }
375
376 std::cout << "\nTest flood fill is ok!" << std::endl;
377 return EXIT_SUCCESS;
378 }
379 catch (const vpException &e) {
380 std::cerr << "Catch an exception: " << e.what() << std::endl;
381 return EXIT_FAILURE;
382 }
383#else
384 (void)argc;
385 (void)argv;
386 std::cout << "Install OpenCV imgproc module required by this test" << std::endl;
387 return EXIT_SUCCESS;
388#endif
389}
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ fatalError
Fatal error.
Definition vpException.h:72
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:131
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:181
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(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)
VISP_EXPORT double measureTimeMs()