Visual Servoing Platform version 3.5.0
testContours.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 contours extraction.
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 contours extraction.\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
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], NULL, ipath, opath, user);
127 return false;
128 break;
129
130 case 'c':
131 case 'd':
132 break;
133
134 default:
135 usage(argv[0], optarg_, ipath, opath, user);
136 return false;
137 break;
138 }
139 }
140
141 if ((c == 1) || (c == -1)) {
142 // standalone param or error
143 usage(argv[0], NULL, ipath, opath, user);
144 std::cerr << "ERROR: " << std::endl;
145 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
146 return false;
147 }
148
149 return true;
150}
151
152void printImage(const vpImage<unsigned char> &I, const std::string &name)
153{
154 std::cout << "\n" << name << ":" << std::endl;
155
156 std::cout << " ";
157 for (unsigned int j = 0; j < I.getWidth(); j++) {
158 std::cout << std::setfill(' ') << std::setw(2) << j << " ";
159 }
160 std::cout << std::endl;
161
162 for (unsigned int i = 0; i < I.getHeight(); i++) {
163 std::cout << std::setfill(' ') << std::setw(2) << i << " ";
164
165 for (unsigned int j = 0; j < I.getWidth(); j++) {
166 std::cout << std::setfill(' ') << std::setw(2) << static_cast<unsigned int>(I[i][j]) << " ";
167 }
168
169 std::cout << std::endl;
170 }
171}
172
173void displayContourInfo(const vp::vpContour &contour, int level)
174{
175 std::cout << "\nContour:" << std::endl;
176 std::cout << "\tlevel: " << level << std::endl;
177 std::cout << "\tcontour type: " << (contour.m_contourType == vp::CONTOUR_OUTER ? "outer contour" : "hole contour")
178 << std::endl;
179 std::cout << "\tnb children: " << contour.m_children.size() << std::endl;
180
181 for (std::vector<vp::vpContour *>::const_iterator it = contour.m_children.begin(); it != contour.m_children.end();
182 ++it) {
183 displayContourInfo(**it, level + 1);
184 }
185}
186
187int main(int argc, const char **argv)
188{
189 try {
190 std::string env_ipath;
191 std::string opt_ipath;
192 std::string opt_opath;
193 std::string ipath;
194 std::string opath;
195 std::string filename;
196 std::string username;
197
198 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
199 // environment variable value
201
202 // Set the default input path
203 if (!env_ipath.empty())
204 ipath = env_ipath;
205
206// Set the default output path
207#if defined(_WIN32)
208 opt_opath = "C:/temp";
209#else
210 opt_opath = "/tmp";
211#endif
212
213 // Get the user login name
214 vpIoTools::getUserName(username);
215
216 // Read the command line options
217 if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
218 exit(EXIT_FAILURE);
219 }
220
221 // Get the option values
222 if (!opt_ipath.empty())
223 ipath = opt_ipath;
224 if (!opt_opath.empty())
225 opath = opt_opath;
226
227 // Append to the output path string, the login name of the user
228 opath = vpIoTools::createFilePath(opath, username);
229
230 // Test if the output path exist. If no try to create it
231 if (vpIoTools::checkDirectory(opath) == false) {
232 try {
233 // Create the dirname
235 } catch (...) {
236 usage(argv[0], NULL, ipath, opt_opath, username);
237 std::cerr << std::endl << "ERROR:" << std::endl;
238 std::cerr << " Cannot create " << opath << std::endl;
239 std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
240 exit(EXIT_FAILURE);
241 }
242 }
243
244 // Compare ipath and env_ipath. If they differ, we take into account
245 // the input path comming from the command line option
246 if (!opt_ipath.empty() && !env_ipath.empty()) {
247 if (ipath != env_ipath) {
248 std::cout << std::endl << "WARNING: " << std::endl;
249 std::cout << " Since -i <visp image path=" << ipath << "> "
250 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
251 << " we skip the environment variable." << std::endl;
252 }
253 }
254
255 // Test if an input path is set
256 if (opt_ipath.empty() && env_ipath.empty()) {
257 usage(argv[0], NULL, ipath, opt_opath, username);
258 std::cerr << std::endl << "ERROR:" << std::endl;
259 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
260 << " environment variable to specify the location of the " << std::endl
261 << " image path where test images are located." << std::endl
262 << std::endl;
263 exit(EXIT_FAILURE);
264 }
265
266 //
267 // Here starts really the test
268 //
269
270 unsigned char image_data[14 * 10] = {
271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
272 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
274 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
275
276 vpImage<unsigned char> I_test_data(image_data, 14, 10, true);
277 std::cout << "Test with image data:" << std::endl;
278 printImage(I_test_data, "I_test_data");
279
280 vp::vpContour vp_contours;
281 std::vector<std::vector<vpImagePoint> > contours;
282 double t = vpTime::measureTimeMs();
283 vp::findContours(I_test_data, vp_contours, contours);
284 t = vpTime::measureTimeMs() - t;
285
286 displayContourInfo(vp_contours, 0);
287 std::cout << "ViSP: nb contours=" << contours.size() << " ; t=" << t << " ms" << std::endl;
288
289 // Read Klimt.ppm
290 filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
292 std::cout << "Read image: " << filename << std::endl;
293 vpImageIo::read(I, filename);
294 vpImageTools::binarise(I, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)1,
295 (unsigned char)1);
296
298 for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
299 I2.bitmap[cpt] = 255 * I.bitmap[cpt];
300 }
301 filename = vpIoTools::createFilePath(opath, "Klimt_contours_binarise.pgm");
302 vpImageIo::write(I2, filename);
303
305 vp::findContours(I, vp_contours, contours);
306 t = vpTime::measureTimeMs() - t;
307
308 displayContourInfo(vp_contours, 0);
309 std::cout << "\nTest with Klimt image:" << std::endl;
310 std::cout << "ViSP: nb contours=" << contours.size() << " ; t=" << t << " ms" << std::endl;
311
312 // Draw and save
313 vpImage<unsigned char> I_draw_contours(I2.getHeight(), I2.getWidth(), 0);
314 vp::drawContours(I_draw_contours, contours);
315
316 filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted.pgm");
317 vpImageIo::write(I_draw_contours, filename);
318
319 vpImage<vpRGBa> I_draw_contours_color(I2.getHeight(), I2.getWidth(), vpRGBa(0, 0, 0));
320 vp::drawContours(I_draw_contours_color, contours, vpColor::red);
321
322 filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_color.ppm");
323 vpImageIo::write(I_draw_contours_color, filename);
324
325 // Test retrieve list
326 vp::findContours(I, vp_contours, contours, vp::CONTOUR_RETR_LIST);
327 vpImage<unsigned char> I_draw_contours_list(I2.getHeight(), I2.getWidth(), 0);
328
329 vpImage<unsigned char> I_tmp_list(I.getHeight(), I.getWidth(), 0);
330 vp::drawContours(I_tmp_list, contours);
331
332 contours.clear();
333 for (std::vector<vp::vpContour *>::const_iterator it = vp_contours.m_children.begin();
334 it != vp_contours.m_children.end(); ++it) {
335 contours.push_back((*it)->m_points);
336 }
337
338 vp::drawContours(I_draw_contours_list, contours);
339 std::cout << "(I_tmp_list == I_draw_contours_list)? " << (I_tmp_list == I_draw_contours_list) << std::endl;
340
341 filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_list.pgm");
342 vpImageIo::write(I_draw_contours_list, filename);
343
344 // Test retrieve external
345 vp::findContours(I, vp_contours, contours, vp::CONTOUR_RETR_EXTERNAL);
346 vpImage<unsigned char> I_draw_contours_external(I2.getHeight(), I2.getWidth(), 0);
347
348 vpImage<unsigned char> I_tmp_external(I.getHeight(), I.getWidth(), 0);
349 vp::drawContours(I_tmp_external, contours);
350
351 contours.clear();
352 for (std::vector<vp::vpContour *>::const_iterator it = vp_contours.m_children.begin();
353 it != vp_contours.m_children.end(); ++it) {
354 contours.push_back((*it)->m_points);
355 }
356
357 vp::drawContours(I_draw_contours_external, contours);
358 std::cout << "(I_tmp_external == I_draw_contours_external)? " << (I_tmp_external == I_draw_contours_external)
359 << std::endl;
360
361 filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_external.pgm");
362 vpImageIo::write(I_draw_contours_external, filename);
363
364 // Test fillHoles
365 vpImage<unsigned char> I_holes = I_draw_contours_external;
366 vpImageTools::binarise(I_holes, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)255,
367 (unsigned char)255);
368
370 vp::fillHoles(I_holes);
371 t = vpTime::measureTimeMs() - t;
372 std::cout << "\nFill Holes: " << t << " ms" << std::endl;
373
374 filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_external_fill_holes.pgm");
375 vpImageIo::write(I_holes, filename);
376
377#if VISP_HAVE_OPENCV_VERSION >= 0x030000
378 cv::Mat matImg;
379 vpImageConvert::convert(I, matImg);
380
381 std::vector<std::vector<cv::Point> > contours_opencv;
382 double t_opencv = vpTime::measureTimeMs();
383 cv::findContours(matImg, contours_opencv, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
384 t_opencv = vpTime::measureTimeMs() - t_opencv;
385 std::cout << "\nOpenCV: nb contours=" << contours_opencv.size() << " ; t_opencv=" << t_opencv << " ms" << std::endl;
386
387 vpImage<unsigned char> I_draw_contours_opencv(I.getHeight(), I.getWidth(), 0);
388 for (std::vector<std::vector<cv::Point> >::const_iterator it1 = contours_opencv.begin();
389 it1 != contours_opencv.end(); ++it1) {
390 for (std::vector<cv::Point>::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) {
391 I_draw_contours_opencv[it2->y][it2->x] = 255;
392 }
393 }
394
395 std::cout << "(I_draw_contours_opencv == I_drawContours)? " << (I_draw_contours_opencv == I_draw_contours)
396 << std::endl;
397
398 filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_opencv.pgm");
399 vpImageIo::write(I_draw_contours_opencv, filename);
400
401 // Test retrieve list
402 vpImageConvert::convert(I, matImg);
403 contours_opencv.clear();
404 cv::findContours(matImg, contours_opencv, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
405
406 I_draw_contours_opencv = 0;
407 for (std::vector<std::vector<cv::Point> >::const_iterator it1 = contours_opencv.begin();
408 it1 != contours_opencv.end(); ++it1) {
409 for (std::vector<cv::Point>::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) {
410 I_draw_contours_opencv[it2->y][it2->x] = 255;
411 }
412 }
413
414 std::cout << "(I_draw_contours_opencv == I_draw_contours_list)? "
415 << (I_draw_contours_opencv == I_draw_contours_list) << std::endl;
416
417 // Test retrieve external
418 vpImageConvert::convert(I, matImg);
419 contours_opencv.clear();
420 cv::findContours(matImg, contours_opencv, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
421
422 I_draw_contours_opencv = 0;
423 for (std::vector<std::vector<cv::Point> >::const_iterator it1 = contours_opencv.begin();
424 it1 != contours_opencv.end(); ++it1) {
425 for (std::vector<cv::Point>::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) {
426 I_draw_contours_opencv[it2->y][it2->x] = 255;
427 }
428 }
429
430 std::cout << "(I_draw_contours_opencv == I_draw_contours_external)? "
431 << (I_draw_contours_opencv == I_draw_contours_external) << std::endl;
432#endif
433
434 return EXIT_SUCCESS;
435 } catch (const vpException &e) {
436 std::cerr << "Catch an exception: " << e.what() << std::endl;
437 return EXIT_FAILURE;
438 }
439}
static const vpColor red
Definition: vpColor.h:217
error that can be emited by ViSP classes.
Definition: vpException.h:72
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
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
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
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
Definition: vpRGBa.h:67
VISP_EXPORT void findContours(const vpImage< unsigned char > &I_original, vpContour &contours, std::vector< std::vector< vpImagePoint > > &contourPts, const vpContourRetrievalType &retrievalMode=vp::CONTOUR_RETR_TREE)
Definition: vpContours.cpp:300
VISP_EXPORT void drawContours(vpImage< unsigned char > &I, const std::vector< std::vector< vpImagePoint > > &contours, unsigned char grayValue=255)
Definition: vpContours.cpp:250
VISP_EXPORT void fillHoles(vpImage< unsigned char > &I)
Definition: vpMorph.cpp:54
VISP_EXPORT double measureTimeMs()
@ CONTOUR_RETR_LIST
Definition: vpContours.h:167
@ CONTOUR_RETR_EXTERNAL
Definition: vpContours.h:168
@ CONTOUR_OUTER
Definition: vpContours.h:160
vpContourType m_contourType
Definition: vpContours.h:173
std::vector< vpContour * > m_children
Definition: vpContours.h:172