Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
histogram.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  * Example of Histogram manipulation.
33  *
34  * Author:
35  * Fabien Spindler
36  *
37  *****************************************************************************/
38 
45 #include <visp3/core/vpDebug.h>
46 #include <visp3/core/vpHistogram.h>
47 #include <visp3/core/vpImage.h>
48 #include <visp3/core/vpIoTools.h>
49 #include <visp3/io/vpImageIo.h>
50 #include <visp3/io/vpParseArgv.h>
51 
52 #include <iomanip>
53 #include <sstream>
54 #include <stdio.h>
55 #include <stdlib.h>
56 
57 // List of allowed command line options
58 #define GETOPTARGS "i:o:h"
59 
78 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
79 {
80  fprintf(stdout, "\n\
81 Read an image on the disk, display it using X11, display some\n\
82 features (line, circle, caracters) in overlay and finaly write \n\
83 the image and the overlayed features in an image on the disk.\n\
84 \n\
85 SYNOPSIS\n\
86  %s [-i <input image path>] [-o <output histogram path>]\n\
87  [-h]\n\
88 ", name);
89 
90  fprintf(stdout, "\n\
91 OPTIONS: Default\n\
92  -i <input image path> %s\n\
93  Set image input path.\n\
94  From this path read \"Klimt/Klimt.pgm\"\n\
95  image.\n\
96  Setting the VISP_INPUT_IMAGE_PATH environment\n\
97  variable produces the same behaviour than using\n\
98  this option.\n\
99 \n\
100  -o <output histogram path> %s\n\
101  From this directory, creates the \"%s\"\n\
102  subdirectory depending on the username, where \n\
103  \"histogram.txt\" is saved.\n\
104 \n\
105  -h\n\
106  Print the help.\n\n", ipath.c_str(), opath.c_str(), user.c_str());
107 
108  if (badparam) {
109  fprintf(stderr, "ERROR: \n");
110  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
111  }
112 }
126 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, const std::string &user)
127 {
128  const char *optarg_;
129  int c;
130  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
131 
132  switch (c) {
133  case 'i':
134  ipath = optarg_;
135  break;
136  case 'o':
137  opath = optarg_;
138  break;
139  case 'h':
140  usage(argv[0], NULL, ipath, opath, user);
141  return false;
142  break;
143 
144  default:
145  usage(argv[0], optarg_, ipath, opath, user);
146  return false;
147  break;
148  }
149  }
150 
151  if ((c == 1) || (c == -1)) {
152  // standalone param or error
153  usage(argv[0], NULL, ipath, opath, user);
154  std::cerr << "ERROR: " << std::endl;
155  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
156  return false;
157  }
158 
159  return true;
160 }
161 
162 int main(int argc, const char **argv)
163 {
164  try {
165  std::string env_ipath;
166  std::string opt_ipath;
167  std::string opt_opath;
168  std::string ipath;
169  std::string opath;
170  std::string filename;
171  std::string username;
172 
173  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
174  // environment variable value
175  env_ipath = vpIoTools::getViSPImagesDataPath();
176 
177  // Set the default input path
178  if (!env_ipath.empty())
179  ipath = env_ipath;
180 
181 // Set the default output path
182 #if defined(_WIN32)
183  opt_opath = "C:/temp";
184 #else
185  opt_opath = "/tmp";
186 #endif
187 
188  // Get the user login name
189  vpIoTools::getUserName(username);
190 
191  // Read the command line options
192  if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
193  exit(-1);
194  }
195 
196  // Get the option values
197  if (!opt_ipath.empty())
198  ipath = opt_ipath;
199  if (!opt_opath.empty())
200  opath = opt_opath;
201 
202  // Append to the output path string, the login name of the user
203  std::string dirname = vpIoTools::createFilePath(opath, username);
204 
205  // Test if the output path exist. If no try to create it
206  if (vpIoTools::checkDirectory(dirname) == false) {
207  try {
208  // Create the dirname
209  vpIoTools::makeDirectory(dirname);
210  } catch (...) {
211  usage(argv[0], NULL, ipath, opath, username);
212  std::cerr << std::endl << "ERROR:" << std::endl;
213  std::cerr << " Cannot create " << dirname << std::endl;
214  std::cerr << " Check your -o " << opath << " option " << std::endl;
215  exit(-1);
216  }
217  }
218 
219  // Compare ipath and env_ipath. If they differ, we take into account
220  // the input path comming from the command line option
221  if (opt_ipath.empty()) {
222  if (ipath != env_ipath) {
223  std::cout << std::endl << "WARNING: " << std::endl;
224  std::cout << " Since -i <visp image path=" << ipath << "> "
225  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
226  << " we skip the environment variable." << std::endl;
227  }
228  }
229 
230  // Test if an input path is set
231  if (opt_ipath.empty() && env_ipath.empty()) {
232  usage(argv[0], NULL, ipath, opath, username);
233  std::cerr << std::endl << "ERROR:" << std::endl;
234  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
235  << " environment variable to specify the location of the " << std::endl
236  << " image path where test images are located." << std::endl
237  << std::endl;
238  exit(-1);
239  }
240 
241  // Create a grey level image
243 
244  // Load a grey image from the disk
245  filename = ipath;
246  if (opt_ipath.empty())
247  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
248 
249  std::cout << "Read: " << filename << std::endl;
250  vpImageIo::read(I, filename);
251 
252  unsigned char distance = 60;
253  vpHistogram h;
254 
255  // Computes the histogram from the image
256  h.calculate(I);
257 
258  // Save the histogram
259  filename = dirname + vpIoTools::path("/histogram.txt");
260  std::cout << "Save the histogram in: " << filename << std::endl;
261  h.write(filename);
262 
263  // Smooth the histogram
264  h.smooth();
265  // Save the histogram
266  filename = dirname + vpIoTools::path("/histogram_smoothed.txt");
267  std::cout << "Save the smoothed histogram in: " << filename << std::endl;
268  h.write(filename);
269 
270  std::list<vpHistogramPeak> peaks;
271  unsigned int nbpeaks = 0;
272 
273  // get all the histogram peaks
274  nbpeaks = h.getPeaks(peaks);
275 
276  vpTRACE("List of peaks");
277  vpTRACE("Nb peaks: %d", nbpeaks);
278  if (nbpeaks) {
279  for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it) {
280  vpHistogramPeak p = *it;
281  vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
282  }
283  }
284 
285  // sort all the histogram peaks list to have the highest peak at the
286  // beginning of the list, the smallest at the end.
287  nbpeaks = h.sort(peaks);
288 
289  vpTRACE("Sorted list of peaks");
290  vpTRACE("Nb peaks: %d", nbpeaks);
291  if (nbpeaks) {
292  for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it) {
293  vpHistogramPeak p = *it;
294  vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
295  }
296  }
297 
298  // Get the two highest histogram peaks. peak1 is the highest
299  vpHistogramPeak peak1, peak2;
300  nbpeaks = h.getPeaks(distance, peak1, peak2);
301  if (nbpeaks != 2) {
302  std::cout << "Not a bimodal histogram..." << std::endl;
303  } else {
304  vpTRACE("Bimodal histogram: main peak1: %d-%d second peak2: %d-%d", peak1.getLevel(), peak1.getValue(),
305  peak2.getLevel(), peak2.getValue());
306  }
307 
308  // Get the valey between the two highest peaks
309  vpHistogramValey valey;
310  if (h.getValey(peak1, peak2, valey) == false) {
311  vpTRACE("No valey found...");
312  } else {
313  vpTRACE("Valey: %d-%d", valey.getLevel(), valey.getValue());
314  }
315 
316  vpHistogramValey valeyl, valeyr;
317 
318  {
319  // Search the two valeys around peak1
320  unsigned ret = h.getValey(distance, peak1, valeyl, valeyr);
321  if (ret == 0x00) {
322  vpTRACE("No left and right valey for peak %d-%d...", peak1.getLevel(), peak1.getValue());
323  } else if (ret == 0x10) {
324  vpTRACE("No right valey for peak %d-%d...", peak1.getLevel(), peak1.getValue());
325  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
326  } else if (ret == 0x01) {
327  vpTRACE("No left valey for peak %d-%d...", peak1.getLevel(), peak1.getValue());
328  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
329  } else if (ret == 0x11) {
330  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
331  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
332  }
333  }
334  {
335  // Search the two valeys around peak2
336  unsigned ret = h.getValey(distance, peak2, valeyl, valeyr);
337  if (ret == 0x00) {
338  vpTRACE("No left and right valey for peak %d-%d...", peak2.getLevel(), peak2.getValue());
339  } else if (ret == 0x10) {
340  vpTRACE("No right valey for peak %d-%d...", peak2.getLevel(), peak2.getValue());
341  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
342  } else if (ret == 0x01) {
343  vpTRACE("No left valey for peak %d-%d...", peak2.getLevel(), peak2.getValue());
344  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
345  } else if (ret == 0x11) {
346  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
347  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
348  }
349  }
350 
352  // get the valey between the two highest peaks. Here we don't know
353  // which of peakl or peakr is the highest.
354  vpHistogramPeak peakl, peakr;
355  if (h.getPeaks(distance, peakl, peakr, valey) == false) {
356  std::cout << "Not a bimodal histogram..." << std::endl;
357  } else {
358  vpTRACE("Bimodal histogram: valey %d-%d for peakl: %d-%d peakr: %d-%d", valey.getLevel(), valey.getValue(),
359  peakl.getLevel(), peakl.getValue(), peakr.getLevel(), peakr.getValue());
360  }
361  return EXIT_SUCCESS;
362  } catch (const vpException &e) {
363  std::cout << "Catch an exception: " << e << std::endl;
364  return EXIT_FAILURE;
365  }
366 }
unsigned getPeaks(std::list< vpHistogramPeak > &peaks)
static bool checkDirectory(const char *dirname)
Definition: vpIoTools.cpp:467
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1316
unsigned getValue() const
error that can be emited by ViSP classes.
Definition: vpException.h:71
static std::string path(const char *pathname)
Definition: vpIoTools.cpp:941
Class to compute a gray level image histogram.
Definition: vpHistogram.h:112
Declaration of the peak (maximum value) in a gray level image histogram.
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
static void makeDirectory(const char *dirname)
Definition: vpIoTools.cpp:597
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1541
void smooth(const unsigned int fsize=3)
#define vpTRACE
Definition: vpDebug.h:416
void calculate(const vpImage< unsigned char > &I, const unsigned int nbins=256, const unsigned int nbThreads=1)
static std::string getUserName()
Definition: vpIoTools.cpp:298
unsigned sort(std::list< vpHistogramPeak > &peaks)
unsigned char getLevel() const
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:207
bool write(const std::string &filename)
Declaration of the valey (minimum value) in a gray level image histogram.
unsigned getValey(std::list< vpHistogramValey > &valey)