Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
histogram.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2023 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 https://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 *
35*****************************************************************************/
36
43#include <visp3/core/vpDebug.h>
44#include <visp3/core/vpHistogram.h>
45#include <visp3/core/vpImage.h>
46#include <visp3/core/vpIoTools.h>
47#include <visp3/io/vpImageIo.h>
48#include <visp3/io/vpParseArgv.h>
49
50#include <iomanip>
51#include <sstream>
52#include <stdio.h>
53#include <stdlib.h>
54
55// List of allowed command line options
56#define GETOPTARGS "i:o:h"
57
76void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
77{
78 fprintf(stdout, "\n\
79Read an image on the disk, display it using X11, display some\n\
80features (line, circle, characters) in overlay and finally write \n\
81the image and the overlayed features in an image on the disk.\n\
82\n\
83SYNOPSIS\n\
84 %s [-i <input image path>] [-o <output histogram path>]\n\
85 [-h]\n\
86",
87 name);
88
89 fprintf(stdout, "\n\
90OPTIONS: Default\n\
91 -i <input image path> %s\n\
92 Set image input path.\n\
93 From this path read \"Klimt/Klimt.pgm\"\n\
94 image.\n\
95 Setting the VISP_INPUT_IMAGE_PATH environment\n\
96 variable produces the same behaviour than using\n\
97 this option.\n\
98\n\
99 -o <output histogram path> %s\n\
100 From this directory, creates the \"%s\"\n\
101 subdirectory depending on the username, where \n\
102 \"histogram.txt\" is saved.\n\
103\n\
104 -h\n\
105 Print the help.\n\n",
106 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}
126bool 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
162int 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
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 return EXIT_FAILURE;
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
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 return EXIT_FAILURE;
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 return EXIT_FAILURE;
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}
error that can be emitted by ViSP classes.
Definition vpException.h:59
Declaration of the peak (maximum value) in a gray level image histogram.
unsigned getValue() const
unsigned char getLevel() const
Declaration of the valey (minimum value) in a gray level image histogram.
unsigned char getLevel() const
unsigned getValue() const
Class to compute a gray level image histogram.
unsigned getPeaks(std::list< vpHistogramPeak > &peaks)
void smooth(unsigned int fsize=3)
void calculate(const vpImage< unsigned char > &I, unsigned int nbins=256, unsigned int nbThreads=1)
unsigned sort(std::list< vpHistogramPeak > &peaks)
unsigned getValey(std::list< vpHistogramValey > &valey)
bool write(const std::string &filename)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
Definition vpImage.h:135
static std::string getViSPImagesDataPath()
static std::string path(const std::string &pathname)
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)
#define vpTRACE
Definition vpDebug.h:411