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