ViSP  2.9.0
histogram.cpp
1 /****************************************************************************
2  *
3  * $Id: histogram.cpp 4658 2014-02-09 09:50:14Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Example of Histogram manipulation.
36  *
37  * Author:
38  * Fabien Spindler
39  *
40  *****************************************************************************/
41 
51 #include <visp/vpDebug.h>
52 #include <visp/vpImage.h>
53 #include <visp/vpImageIo.h>
54 #include <visp/vpHistogram.h>
55 #include <visp/vpParseArgv.h>
56 #include <visp/vpIoTools.h>
57 
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <sstream>
61 #include <iomanip>
62 
63 // List of allowed command line options
64 #define GETOPTARGS "i:o:h"
65 
66 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user);
67 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user);
68 
87 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
88 {
89  fprintf(stdout, "\n\
90 Read an image on the disk, display it using X11, display some\n\
91 features (line, circle, caracters) in overlay and finaly write \n\
92 the image and the overlayed features in an image on the disk.\n\
93 \n\
94 SYNOPSIS\n\
95  %s [-i <input image path>] [-o <output histogram path>]\n\
96  [-h]\n\
97 ", name);
98 
99  fprintf(stdout, "\n\
100 OPTIONS: Default\n\
101  -i <input image path> %s\n\
102  Set image input path.\n\
103  From this path read \"ViSP-images/Klimt/Klimt.pgm\"\n\
104  image.\n\
105  Setting the VISP_INPUT_IMAGE_PATH environment\n\
106  variable produces the same behaviour than using\n\
107  this option.\n\
108 \n\
109  -o <output histogram path> %s\n\
110  From this directory, creates the \"%s\"\n\
111  subdirectory depending on the username, where \n\
112  \"histogram.txt\" is saved.\n\
113 \n\
114  -h\n\
115  Print the help.\n\n",
116  ipath.c_str(), opath.c_str(), user.c_str());
117 
118  if (badparam) {
119  fprintf(stderr, "ERROR: \n" );
120  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
121  }
122 
123 }
137 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user)
138 {
139  const char *optarg_;
140  int c;
141  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
142 
143  switch (c) {
144  case 'i': ipath = optarg_; break;
145  case 'o': opath = optarg_; break;
146  case 'h': usage(argv[0], NULL, ipath, opath, user); return false; break;
147 
148  default:
149  usage(argv[0], optarg_, ipath, opath, user); return false; break;
150  }
151  }
152 
153  if ((c == 1) || (c == -1)) {
154  // standalone param or error
155  usage(argv[0], NULL, ipath, opath, user);
156  std::cerr << "ERROR: " << std::endl;
157  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
158  return false;
159  }
160 
161  return true;
162 }
163 
164 int
165 main(int argc, const char ** argv)
166 {
167  try {
168  std::string env_ipath;
169  std::string opt_ipath;
170  std::string opt_opath;
171  std::string ipath;
172  std::string opath;
173  std::string filename;
174  std::string username;
175 
176  // Get the VISP_IMAGE_PATH environment variable value
177  char *ptenv = getenv("VISP_INPUT_IMAGE_PATH");
178  if (ptenv != NULL)
179  env_ipath = ptenv;
180  // std::cout << "env_ipath: " << env_ipath << std::endl;
181 
182  // Set the default input path
183  if (! env_ipath.empty())
184  ipath = env_ipath;
185 
186  // Set the default output path
187 #if defined(_WIN32)
188  opt_opath = "C:/temp";
189 #else
190  opt_opath = "/tmp";
191 #endif
192 
193  // Get the user login name
194  vpIoTools::getUserName(username);
195 
196  // Read the command line options
197  if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
198  exit (-1);
199  }
200 
201  // Get the option values
202  if (!opt_ipath.empty())
203  ipath = opt_ipath;
204  if (!opt_opath.empty())
205  opath = opt_opath;
206 
207  // Append to the output path string, the login name of the user
208  std::string dirname = opath + vpIoTools::path("/") + username;
209 
210  // Test if the output path exist. If no try to create it
211  if (vpIoTools::checkDirectory(dirname) == false) {
212  try {
213  // Create the dirname
214  vpIoTools::makeDirectory(dirname);
215  }
216  catch (...) {
217  usage(argv[0], NULL, ipath, opath, username);
218  std::cerr << std::endl
219  << "ERROR:" << std::endl;
220  std::cerr << " Cannot create " << dirname << std::endl;
221  std::cerr << " Check your -o " << opath << " option " << std::endl;
222  exit(-1);
223  }
224  }
225 
226  // Compare ipath and env_ipath. If they differ, we take into account
227  // the input path comming from the command line option
228  if (opt_ipath.empty()) {
229  if (ipath != env_ipath) {
230  std::cout << std::endl
231  << "WARNING: " << std::endl;
232  std::cout << " Since -i <visp image path=" << ipath << "> "
233  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
234  << " we skip the environment variable." << std::endl;
235  }
236  }
237 
238  // Test if an input path is set
239  if (opt_ipath.empty() && env_ipath.empty()){
240  usage(argv[0], NULL, ipath, opath, username);
241  std::cerr << std::endl
242  << "ERROR:" << std::endl;
243  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
244  << std::endl
245  << " environment variable to specify the location of the " << std::endl
246  << " image path where test images are located." << std::endl << std::endl;
247  exit(-1);
248  }
249 
250  // Create a grey level image
252 
253  // Load a grey image from the disk
254  filename = ipath;
255  if (opt_ipath.empty())
256  filename += vpIoTools::path("/ViSP-images/Klimt/Klimt.pgm");
257 
258  std::cout << "Read: " << filename << std::endl;
259  vpImageIo::read(I, filename) ;
260 
261  unsigned char distance = 60;
262  vpHistogram h;
263 
264  // Computes the histogram from the image
265  h.calculate(I);
266 
267  // Save the histogram
268  filename = dirname + vpIoTools::path("/histogram.txt");
269  std::cout << "Save the histogram in: " << filename << std::endl;
270  h.write(filename);
271 
272  // Smooth the histogram
273  h.smooth();
274  // Save the histogram
275  filename = dirname + vpIoTools::path("/histogram_smoothed.txt");
276  std::cout << "Save the smoothed histogram in: " << filename << std::endl;
277  h.write(filename);
278 
279  std::list<vpHistogramPeak> peaks;
280  unsigned int nbpeaks = 0;
281 
282  // get all the histogram peaks
283  nbpeaks = h.getPeaks(peaks);
284 
285  vpTRACE("List of peaks");
286  vpTRACE("Nb peaks: %d", nbpeaks);
287  if (nbpeaks) {
288  for(std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it)
289  {
290  vpHistogramPeak p = *it;
291  vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
292  }
293  }
294 
295  // sort all the histogram peaks list to have the highest peak at the
296  // beginning of the list, the smallest at the end.
297  nbpeaks = h.sort(peaks);
298 
299  vpTRACE("Sorted list of peaks");
300  vpTRACE("Nb peaks: %d", nbpeaks);
301  if (nbpeaks) {
302  for(std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it)
303  {
304  vpHistogramPeak p = *it;
305  vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
306  }
307  }
308 
309  // Get the two highest histogram peaks. peak1 is the highest
310  vpHistogramPeak peak1, peak2;
311  nbpeaks = h.getPeaks(distance, peak1, peak2);
312  if (nbpeaks != 2) {
313  std::cout << "Not a bimodal histogram..." << std::endl;
314  }
315  else {
316  vpTRACE("Bimodal histogram: main peak1: %d-%d second peak2: %d-%d",
317  peak1.getLevel(), peak1.getValue(),
318  peak2.getLevel(), peak2.getValue());
319  }
320 
321  // Get the valey between the two highest peaks
322  vpHistogramValey valey;
323  if (h.getValey(peak1, peak2, valey) == false) {
324  vpTRACE("No valey found...");
325  }
326  else {
327  vpTRACE("Valey: %d-%d", valey.getLevel(), valey.getValue());
328  }
329 
330  vpHistogramValey valeyl, valeyr;
331 
332  {
333  // Search the two valeys around peak1
334  unsigned ret = h.getValey(distance, peak1, valeyl, valeyr);
335  if (ret == 0x00) {
336  vpTRACE("No left and right valey for peak %d-%d...",
337  peak1.getLevel(), peak1.getValue());
338  }
339  else if (ret == 0x10) {
340  vpTRACE("No right valey for peak %d-%d...",
341  peak1.getLevel(), peak1.getValue());
342  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
343  }
344  else if (ret == 0x01) {
345  vpTRACE("No left valey for peak %d-%d...",
346  peak1.getLevel(), peak1.getValue());
347  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
348  }
349  else if (ret == 0x11) {
350  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
351  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
352  }
353  }
354  {
355  // Search the two valeys around peak2
356  unsigned ret = h.getValey(distance, peak2, valeyl, valeyr);
357  if (ret == 0x00) {
358  vpTRACE("No left and right valey for peak %d-%d...",
359  peak2.getLevel(), peak2.getValue());
360  }
361  else if (ret == 0x10) {
362  vpTRACE("No right valey for peak %d-%d...",
363  peak2.getLevel(), peak2.getValue());
364  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
365  }
366  else if (ret == 0x01) {
367  vpTRACE("No left valey for peak %d-%d...",
368  peak2.getLevel(), peak2.getValue());
369  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
370  }
371  else if (ret == 0x11) {
372  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
373  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
374  }
375  }
376 
378  // get the valey between the two highest peaks. Here we don't know
379  // which of peakl or peakr is the highest.
380  vpHistogramPeak peakl, peakr;
381  if (h.getPeaks(distance, peakl, peakr, valey) == false) {
382  std::cout << "Not a bimodal histogram..." << std::endl;
383  }
384  else {
385  vpTRACE("Bimodal histogram: valey %d-%d for peakl: %d-%d peakr: %d-%d",
386  valey.getLevel(), valey.getValue(),
387  peakl.getLevel(), peakl.getValue(),
388  peakr.getLevel(), peakr.getValue());
389  }
390  return 0;
391  }
392  catch(vpException e) {
393  std::cout << "Catch an exception: " << e << std::endl;
394  return 1;
395  }
396 }
void calculate(const vpImage< unsigned char > &I)
unsigned getPeaks(std::list< vpHistogramPeak > &peaks)
static bool checkDirectory(const char *dirname)
Definition: vpIoTools.cpp:335
#define vpTRACE
Definition: vpDebug.h:418
unsigned getValue() const
error that can be emited by ViSP classes.
Definition: vpException.h:76
static std::string path(const char *pathname)
Definition: vpIoTools.cpp:715
Class to compute a gray level image histogram.
Definition: vpHistogram.h:115
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:79
unsigned char getLevel() const
static void makeDirectory(const char *dirname)
Definition: vpIoTools.cpp:404
void smooth(const unsigned int fsize=3)
unsigned getValue() const
static std::string getUserName()
Definition: vpIoTools.cpp:140
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:278
Declaration of the valey (minimum value) in a gray level image histogram.
unsigned getValey(std::list< vpHistogramValey > &valey)