Visual Servoing Platform version 3.5.0
testFloodFill.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See http://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Test flood fill algorithm.
33 *
34 * Authors:
35 * Souriya Trinh
36 *
37 *****************************************************************************/
38
39#include <iomanip>
40
41#include <visp3/core/vpImageTools.h>
42#include <visp3/core/vpIoTools.h>
43#include <visp3/imgproc/vpImgproc.h>
44#include <visp3/io/vpImageIo.h>
45#include <visp3/io/vpParseArgv.h>
46
53// List of allowed command line options
54#define GETOPTARGS "cdi:o:h"
55
56void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user);
57bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user);
58
59/*
60 Print the program options.
61
62 \param name : Program name.
63 \param badparam : Bad parameter name.
64 \param ipath: Input image path.
65 \param opath : Output image path.
66 \param user : Username.
67 */
68void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
69{
70 fprintf(stdout, "\n\
71Test flood fill algorithm.\n\
72\n\
73SYNOPSIS\n\
74 %s [-i <input image path>] [-o <output image path>]\n\
75 [-h]\n \
76", name);
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", ipath.c_str(), opath.c_str(), user.c_str());
96
97 if (badparam)
98 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
99}
100
111bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user)
112{
113 const char *optarg_;
114 int c;
115 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
116
117 switch (c) {
118 case 'i':
119 ipath = optarg_;
120 break;
121 case 'o':
122 opath = optarg_;
123 break;
124 case 'h':
125 usage(argv[0], NULL, ipath, opath, user);
126 return false;
127 break;
128
129 case 'c':
130 case 'd':
131 break;
132
133 default:
134 usage(argv[0], optarg_, ipath, opath, user);
135 return false;
136 break;
137 }
138 }
139
140 if ((c == 1) || (c == -1)) {
141 // standalone param or error
142 usage(argv[0], NULL, ipath, opath, user);
143 std::cerr << "ERROR: " << std::endl;
144 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
145 return false;
146 }
147
148 return true;
149}
150
151void printImage(const vpImage<unsigned char> &I, const std::string &name)
152{
153 std::cout << "\n" << name << ":" << std::endl;
154
155 std::cout << " ";
156 for (unsigned int j = 0; j < I.getWidth(); j++) {
157 std::cout << std::setfill(' ') << std::setw(2) << j << " ";
158 }
159 std::cout << std::endl;
160
161 std::cout << std::setfill(' ') << std::setw(3) << "+";
162 for (unsigned int j = 0; j < I.getWidth(); j++) {
163 std::cout << std::setw(3) << "---";
164 }
165 std::cout << std::endl;
166
167 for (unsigned int i = 0; i < I.getHeight(); i++) {
168 std::cout << std::setfill(' ') << std::setw(2) << i << "|";
169
170 for (unsigned int j = 0; j < I.getWidth(); j++) {
171 std::cout << std::setfill(' ') << std::setw(2) << static_cast<unsigned int>(I[i][j]) << " ";
172 }
173
174 std::cout << std::endl;
175 }
176}
177
178int main(int argc, const char **argv)
179{
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 } catch (...) {
227 usage(argv[0], NULL, ipath, opt_opath, username);
228 std::cerr << std::endl << "ERROR:" << std::endl;
229 std::cerr << " Cannot create " << opath << std::endl;
230 std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
231 exit(EXIT_FAILURE);
232 }
233 }
234
235 // Compare ipath and env_ipath. If they differ, we take into account
236 // the input path comming from the command line option
237 if (!opt_ipath.empty() && !env_ipath.empty()) {
238 if (ipath != env_ipath) {
239 std::cout << std::endl << "WARNING: " << std::endl;
240 std::cout << " Since -i <visp image path=" << ipath << "> "
241 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
242 << " we skip the environment variable." << std::endl;
243 }
244 }
245
246 // Test if an input path is set
247 if (opt_ipath.empty() && env_ipath.empty()) {
248 usage(argv[0], NULL, ipath, opt_opath, username);
249 std::cerr << std::endl << "ERROR:" << std::endl;
250 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
251 << " environment variable to specify the location of the " << std::endl
252 << " image path where test images are located." << std::endl
253 << std::endl;
254 exit(EXIT_FAILURE);
255 }
256
257 //
258 // Here starts really the test
259 //
260
261 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,
262 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1,
263 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0};
264 vpImage<unsigned char> I_test_flood_fill_4_connexity(image_data, 8, 8, true);
265 vpImage<unsigned char> I_test_flood_fill_8_connexity = I_test_flood_fill_4_connexity;
266 printImage(I_test_flood_fill_4_connexity, "Test image data");
267
268 unsigned char image_data_check_4_connexity[8 * 8] = {
269 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,
270 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};
271 vpImage<unsigned char> I_check_4_connexity(image_data_check_4_connexity, 8, 8, true);
272
273 unsigned char image_data_check_8_connexity[8 * 8] = {
274 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,
275 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};
276 vpImage<unsigned char> I_check_8_connexity(image_data_check_8_connexity, 8, 8, true);
277
278 // Test flood fill on test data 4-connexity
279 vp::floodFill(I_test_flood_fill_4_connexity, vpImagePoint(2, 2), 0, 1, vpImageMorphology::CONNEXITY_4);
280 printImage(I_test_flood_fill_4_connexity, "I_test_flood_fill_4_connexity");
281
282 if (I_test_flood_fill_4_connexity != I_check_4_connexity) {
283 throw vpException(vpException::fatalError, "Problem with vp::floodFill() and 4-connexity!");
284 }
285 std::cout << "\n(I_test_flood_fill_4_connexity == I_check_4_connexity)? "
286 << (I_test_flood_fill_4_connexity == I_check_4_connexity) << std::endl;
287
288 // Test flood fill on test data 8-connexity
289 vp::floodFill(I_test_flood_fill_8_connexity, vpImagePoint(2, 2), 0, 1, vpImageMorphology::CONNEXITY_8);
290 printImage(I_test_flood_fill_8_connexity, "I_test_flood_fill_8_connexity");
291
292 if (I_test_flood_fill_8_connexity != I_check_8_connexity) {
293 throw vpException(vpException::fatalError, "Problem with vp::floodFill() and 8-connexity!");
294 }
295 std::cout << "\n(I_test_flood_fill_8_connexity == I_check_8_connexity)? "
296 << (I_test_flood_fill_8_connexity == I_check_8_connexity) << std::endl;
297
298 // Read Klimt.ppm
299 filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
301 vpImageIo::read(I_klimt, filename);
302 std::cout << "\nRead image: " << filename << " (" << I_klimt.getWidth() << "x" << I_klimt.getHeight() << ")"
303 << std::endl
304 << std::endl;
305 vpImageTools::binarise(I_klimt, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)255,
306 (unsigned char)255);
307
308 int seed_x = 0;
309 int seed_y = 0;
310
311 vpImage<unsigned char> I_klimt_flood_fill_4_connexity = I_klimt;
312 double t = vpTime::measureTimeMs();
313 vp::floodFill(I_klimt_flood_fill_4_connexity, vpImagePoint(seed_y, seed_x), 0, 255, vpImageMorphology::CONNEXITY_4);
314 t = vpTime::measureTimeMs() - t;
315 std::cout << "Flood fill on Klimt image (4-connexity): " << t << " ms" << std::endl;
316
317 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_4_connexity.pgm");
318 vpImageIo::write(I_klimt_flood_fill_4_connexity, filename);
319
320 vpImage<unsigned char> I_klimt_flood_fill_8_connexity = I_klimt;
322 vp::floodFill(I_klimt_flood_fill_8_connexity, vpImagePoint(seed_y, seed_x), 0, 255, vpImageMorphology::CONNEXITY_8);
323 t = vpTime::measureTimeMs() - t;
324 std::cout << "Flood fill on Klimt image (8-connexity): " << t << " ms" << std::endl;
325 filename = vpIoTools::createFilePath(opath, "Klimt_flood_fill_8_connexity.pgm");
326 vpImageIo::write(I_klimt_flood_fill_8_connexity, filename);
327
328#if VISP_HAVE_OPENCV_VERSION >= 0x020408
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);
337 t = vpTime::measureTimeMs() - t;
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);
350 t = vpTime::measureTimeMs() - t;
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#endif
376
377 std::cout << "\nTest flood fill is ok!" << std::endl;
378 return EXIT_SUCCESS;
379 } catch (const vpException &e) {
380 std::cerr << "Catch an exception: " << e.what() << std::endl;
381 return EXIT_FAILURE;
382 }
383}
error that can be emited by ViSP classes.
Definition: vpException.h:72
@ fatalError
Fatal error.
Definition: vpException.h:96
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)
Definition: vpImageIo.cpp:149
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:293
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, bool useLUT=true)
Definition: vpImageTools.h:459
unsigned int getWidth() const
Definition: vpImage.h:246
unsigned int getHeight() const
Definition: vpImage.h:188
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1365
static bool checkDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:420
static std::string getUserName()
Definition: vpIoTools.cpp:316
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1670
static void makeDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:570
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
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)
Definition: vpFloodFill.cpp:85
VISP_EXPORT double measureTimeMs()