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