ViSP
histogram.cpp
1 /****************************************************************************
2  *
3  * $Id: histogram.cpp 4814 2014-07-31 11:38:39Z 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-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
177  env_ipath = vpIoTools::getViSPImagesDataPath();
178 
179  // Set the default input path
180  if (! env_ipath.empty())
181  ipath = env_ipath;
182 
183  // Set the default output path
184 #if defined(_WIN32)
185  opt_opath = "C:/temp";
186 #else
187  opt_opath = "/tmp";
188 #endif
189 
190  // Get the user login name
191  vpIoTools::getUserName(username);
192 
193  // Read the command line options
194  if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
195  exit (-1);
196  }
197 
198  // Get the option values
199  if (!opt_ipath.empty())
200  ipath = opt_ipath;
201  if (!opt_opath.empty())
202  opath = opt_opath;
203 
204  // Append to the output path string, the login name of the user
205  std::string dirname = vpIoTools::createFilePath(opath, username);
206 
207  // Test if the output path exist. If no try to create it
208  if (vpIoTools::checkDirectory(dirname) == false) {
209  try {
210  // Create the dirname
211  vpIoTools::makeDirectory(dirname);
212  }
213  catch (...) {
214  usage(argv[0], NULL, ipath, opath, username);
215  std::cerr << std::endl
216  << "ERROR:" << std::endl;
217  std::cerr << " Cannot create " << dirname << std::endl;
218  std::cerr << " Check your -o " << opath << " option " << std::endl;
219  exit(-1);
220  }
221  }
222 
223  // Compare ipath and env_ipath. If they differ, we take into account
224  // the input path comming from the command line option
225  if (opt_ipath.empty()) {
226  if (ipath != env_ipath) {
227  std::cout << std::endl
228  << "WARNING: " << std::endl;
229  std::cout << " Since -i <visp image path=" << ipath << "> "
230  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
231  << " we skip the environment variable." << std::endl;
232  }
233  }
234 
235  // Test if an input path is set
236  if (opt_ipath.empty() && env_ipath.empty()){
237  usage(argv[0], NULL, ipath, opath, username);
238  std::cerr << std::endl
239  << "ERROR:" << std::endl;
240  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
241  << std::endl
242  << " environment variable to specify the location of the " << std::endl
243  << " image path where test images are located." << std::endl << std::endl;
244  exit(-1);
245  }
246 
247  // Create a grey level image
249 
250  // Load a grey image from the disk
251  filename = ipath;
252  if (opt_ipath.empty())
253  filename = vpIoTools::createFilePath(ipath, "ViSP-images/Klimt/Klimt.pgm");
254 
255  std::cout << "Read: " << filename << std::endl;
256  vpImageIo::read(I, filename) ;
257 
258  unsigned char distance = 60;
259  vpHistogram h;
260 
261  // Computes the histogram from the image
262  h.calculate(I);
263 
264  // Save the histogram
265  filename = dirname + vpIoTools::path("/histogram.txt");
266  std::cout << "Save the histogram in: " << filename << std::endl;
267  h.write(filename);
268 
269  // Smooth the histogram
270  h.smooth();
271  // Save the histogram
272  filename = dirname + vpIoTools::path("/histogram_smoothed.txt");
273  std::cout << "Save the smoothed histogram in: " << filename << std::endl;
274  h.write(filename);
275 
276  std::list<vpHistogramPeak> peaks;
277  unsigned int nbpeaks = 0;
278 
279  // get all the histogram peaks
280  nbpeaks = h.getPeaks(peaks);
281 
282  vpTRACE("List of peaks");
283  vpTRACE("Nb peaks: %d", nbpeaks);
284  if (nbpeaks) {
285  for(std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it)
286  {
287  vpHistogramPeak p = *it;
288  vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
289  }
290  }
291 
292  // sort all the histogram peaks list to have the highest peak at the
293  // beginning of the list, the smallest at the end.
294  nbpeaks = h.sort(peaks);
295 
296  vpTRACE("Sorted list of peaks");
297  vpTRACE("Nb peaks: %d", nbpeaks);
298  if (nbpeaks) {
299  for(std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it)
300  {
301  vpHistogramPeak p = *it;
302  vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
303  }
304  }
305 
306  // Get the two highest histogram peaks. peak1 is the highest
307  vpHistogramPeak peak1, peak2;
308  nbpeaks = h.getPeaks(distance, peak1, peak2);
309  if (nbpeaks != 2) {
310  std::cout << "Not a bimodal histogram..." << std::endl;
311  }
312  else {
313  vpTRACE("Bimodal histogram: main peak1: %d-%d second peak2: %d-%d",
314  peak1.getLevel(), peak1.getValue(),
315  peak2.getLevel(), peak2.getValue());
316  }
317 
318  // Get the valey between the two highest peaks
319  vpHistogramValey valey;
320  if (h.getValey(peak1, peak2, valey) == false) {
321  vpTRACE("No valey found...");
322  }
323  else {
324  vpTRACE("Valey: %d-%d", valey.getLevel(), valey.getValue());
325  }
326 
327  vpHistogramValey valeyl, valeyr;
328 
329  {
330  // Search the two valeys around peak1
331  unsigned ret = h.getValey(distance, peak1, valeyl, valeyr);
332  if (ret == 0x00) {
333  vpTRACE("No left and right valey for peak %d-%d...",
334  peak1.getLevel(), peak1.getValue());
335  }
336  else if (ret == 0x10) {
337  vpTRACE("No right valey for peak %d-%d...",
338  peak1.getLevel(), peak1.getValue());
339  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
340  }
341  else if (ret == 0x01) {
342  vpTRACE("No left valey for peak %d-%d...",
343  peak1.getLevel(), peak1.getValue());
344  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
345  }
346  else if (ret == 0x11) {
347  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
348  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
349  }
350  }
351  {
352  // Search the two valeys around peak2
353  unsigned ret = h.getValey(distance, peak2, valeyl, valeyr);
354  if (ret == 0x00) {
355  vpTRACE("No left and right valey for peak %d-%d...",
356  peak2.getLevel(), peak2.getValue());
357  }
358  else if (ret == 0x10) {
359  vpTRACE("No right valey for peak %d-%d...",
360  peak2.getLevel(), peak2.getValue());
361  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
362  }
363  else if (ret == 0x01) {
364  vpTRACE("No left valey for peak %d-%d...",
365  peak2.getLevel(), peak2.getValue());
366  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
367  }
368  else if (ret == 0x11) {
369  vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
370  vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
371  }
372  }
373 
375  // get the valey between the two highest peaks. Here we don't know
376  // which of peakl or peakr is the highest.
377  vpHistogramPeak peakl, peakr;
378  if (h.getPeaks(distance, peakl, peakr, valey) == false) {
379  std::cout << "Not a bimodal histogram..." << std::endl;
380  }
381  else {
382  vpTRACE("Bimodal histogram: valey %d-%d for peakl: %d-%d peakr: %d-%d",
383  valey.getLevel(), valey.getValue(),
384  peakl.getLevel(), peakl.getValue(),
385  peakr.getLevel(), peakr.getValue());
386  }
387  return 0;
388  }
389  catch(vpException e) {
390  std::cout << "Catch an exception: " << e << std::endl;
391  return 1;
392  }
393 }
void calculate(const vpImage< unsigned char > &I)
unsigned getPeaks(std::list< vpHistogramPeak > &peaks)
static bool checkDirectory(const char *dirname)
Definition: vpIoTools.cpp:315
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1071
#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:695
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:80
unsigned char getLevel() const
static void makeDirectory(const char *dirname)
Definition: vpIoTools.cpp:384
void smooth(const unsigned int fsize=3)
unsigned getValue() const
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1245
static std::string getUserName()
Definition: vpIoTools.cpp:141
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)