Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
histogram.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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 https://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 */
34
40
41#include <visp3/core/vpConfig.h>
42#include <visp3/core/vpDebug.h>
43#include <visp3/core/vpHistogram.h>
44#include <visp3/core/vpImage.h>
45#include <visp3/core/vpIoTools.h>
46#include <visp3/io/vpImageIo.h>
47#include <visp3/io/vpParseArgv.h>
48
49#include <iomanip>
50#include <sstream>
51#include <stdio.h>
52#include <stdlib.h>
53
54// List of allowed command line options
55#define GETOPTARGS "i:o:h"
56
57#ifdef ENABLE_VISP_NAMESPACE
58using namespace VISP_NAMESPACE_NAME;
59#endif
60
67
79void usage(const char *name, const char *badparam, const std::string &ipath, const std::string &opath, const std::string &user)
80{
81 fprintf(stdout, "\n\
82Read an image on the disk, display it using X11, display some\n\
83features (line, circle, characters) in overlay and finally write \n\
84the image and the overlayed features in an image on the disk.\n\
85\n\
86SYNOPSIS\n\
87 %s [-i <input image path>] [-o <output histogram path>]\n\
88 [-h]\n\
89",
90name);
91
92 fprintf(stdout, "\n\
93OPTIONS: Default\n\
94 -i <input image path> %s\n\
95 Set image input path.\n\
96 From this path read \"Klimt/Klimt.pgm\"\n\
97 image.\n\
98 Setting the VISP_INPUT_IMAGE_PATH environment\n\
99 variable produces the same behaviour than using\n\
100 this option.\n\
101\n\
102 -o <output histogram path> %s\n\
103 From this directory, creates the \"%s\"\n\
104 subdirectory depending on the username, where \n\
105 \"histogram.txt\" is saved.\n\
106\n\
107 -h\n\
108 Print the help.\n\n",
109 ipath.c_str(), opath.c_str(), user.c_str());
110
111 if (badparam) {
112 fprintf(stderr, "ERROR: \n");
113 fprintf(stderr, "\nBad parameter [%s]\n", badparam);
114 }
115}
129bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, const std::string &user)
130{
131 const char *optarg_;
132 int c;
133 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
134
135 switch (c) {
136 case 'i':
137 ipath = optarg_;
138 break;
139 case 'o':
140 opath = optarg_;
141 break;
142 case 'h':
143 usage(argv[0], nullptr, ipath, opath, user);
144 return false;
145
146 default:
147 usage(argv[0], optarg_, ipath, opath, user);
148 return false;
149 }
150 }
151
152 if ((c == 1) || (c == -1)) {
153 // standalone param or error
154 usage(argv[0], nullptr, ipath, opath, user);
155 std::cerr << "ERROR: " << std::endl;
156 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
157 return false;
158 }
159
160 return true;
161}
162
163int main(int argc, const char **argv)
164{
165 try {
166 std::string env_ipath;
167 std::string opt_ipath;
168 std::string opt_opath;
169 std::string ipath;
170 std::string opath;
171 std::string filename;
172 std::string username;
173
174 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
175 // environment variable value
177
178 // Set the default input path
179 if (!env_ipath.empty())
180 ipath = env_ipath;
181
182// Set the default output path
183#if defined(_WIN32)
184 opt_opath = "C:/temp";
185#else
186 opt_opath = "/tmp";
187#endif
188
189 // Get the user login name
190 vpIoTools::getUserName(username);
191
192 // Read the command line options
193 if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
194 return EXIT_FAILURE;
195 }
196
197 // Get the option values
198 if (!opt_ipath.empty())
199 ipath = opt_ipath;
200 if (!opt_opath.empty())
201 opath = opt_opath;
202
203 // Append to the output path string, the login name of the user
204 std::string dirname = vpIoTools::createFilePath(opath, username);
205
206 // Test if the output path exist. If no try to create it
207 if (vpIoTools::checkDirectory(dirname) == false) {
208 try {
209 // Create the dirname
211 }
212 catch (...) {
213 usage(argv[0], nullptr, ipath, opath, username);
214 std::cerr << std::endl << "ERROR:" << std::endl;
215 std::cerr << " Cannot create " << dirname << std::endl;
216 std::cerr << " Check your -o " << opath << " option " << std::endl;
217 return EXIT_FAILURE;
218 }
219 }
220
221 // Compare ipath and env_ipath. If they differ, we take into account
222 // the input path coming from the command line option
223 if (opt_ipath.empty()) {
224 if (ipath != env_ipath) {
225 std::cout << std::endl << "WARNING: " << std::endl;
226 std::cout << " Since -i <visp image path=" << ipath << "> "
227 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
228 << " we skip the environment variable." << std::endl;
229 }
230 }
231
232 // Test if an input path is set
233 if (opt_ipath.empty() && env_ipath.empty()) {
234 usage(argv[0], nullptr, ipath, opath, username);
235 std::cerr << std::endl << "ERROR:" << std::endl;
236 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
237 << " environment variable to specify the location of the " << std::endl
238 << " image path where test images are located." << std::endl
239 << std::endl;
240 return EXIT_FAILURE;
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, "Klimt/Klimt.pgm");
250
251 std::cout << "Read: " << filename << std::endl;
252 vpImageIo::read(I, filename);
253
254 unsigned char distance = 60;
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 vpHistogramPeak p = *it;
283 vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
284 }
285 }
286
287 // sort all the histogram peaks list to have the highest peak at the
288 // beginning of the list, the smallest at the end.
289 nbpeaks = h.sort(peaks);
290
291 vpTRACE("Sorted list of peaks");
292 vpTRACE("Nb peaks: %d", nbpeaks);
293 if (nbpeaks) {
294 for (std::list<vpHistogramPeak>::const_iterator it = peaks.begin(); it != peaks.end(); ++it) {
295 vpHistogramPeak p = *it;
296 vpTRACE("Peak: gray level: %d value: %d", p.getLevel(), p.getValue());
297 }
298 }
299
300 // Get the two highest histogram peaks. peak1 is the highest
301 vpHistogramPeak peak1, peak2;
302 nbpeaks = h.getPeaks(distance, peak1, peak2);
303 if (nbpeaks != 2) {
304 std::cout << "Not a bimodal histogram..." << std::endl;
305 }
306 else {
307 vpTRACE("Bimodal histogram: main peak1: %d-%d second peak2: %d-%d", peak1.getLevel(), peak1.getValue(),
308 peak2.getLevel(), peak2.getValue());
309 }
310
311 // Get the valey between the two highest peaks
312 vpHistogramValey valey;
313 if (h.getValey(peak1, peak2, valey) == false) {
314 vpTRACE("No valey found...");
315 }
316 else {
317 vpTRACE("Valey: %d-%d", valey.getLevel(), valey.getValue());
318 }
319
320 vpHistogramValey valeyl, valeyr;
321
322 {
323 // Search the two valeys around peak1
324 unsigned ret = h.getValey(distance, peak1, valeyl, valeyr);
325 if (ret == 0x00) {
326 vpTRACE("No left and right valey for peak %d-%d...", peak1.getLevel(), peak1.getValue());
327 }
328 else if (ret == 0x10) {
329 vpTRACE("No right valey for peak %d-%d...", peak1.getLevel(), peak1.getValue());
330 vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
331 }
332 else if (ret == 0x01) {
333 vpTRACE("No left valey for peak %d-%d...", peak1.getLevel(), peak1.getValue());
334 vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
335 }
336 else if (ret == 0x11) {
337 vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
338 vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
339 }
340 }
341 {
342 // Search the two valeys around peak2
343 unsigned ret = h.getValey(distance, peak2, valeyl, valeyr);
344 if (ret == 0x00) {
345 vpTRACE("No left and right valey for peak %d-%d...", peak2.getLevel(), peak2.getValue());
346 }
347 else if (ret == 0x10) {
348 vpTRACE("No right valey for peak %d-%d...", peak2.getLevel(), peak2.getValue());
349 vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
350 }
351 else if (ret == 0x01) {
352 vpTRACE("No left valey for peak %d-%d...", peak2.getLevel(), peak2.getValue());
353 vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
354 }
355 else if (ret == 0x11) {
356 vpTRACE("Left valey: %d-%d", valeyl.getLevel(), valeyl.getValue());
357 vpTRACE("Right valey: %d-%d", valeyr.getLevel(), valeyr.getValue());
358 }
359 }
360
362 // get the valey between the two highest peaks. Here we don't know
363 // which of peakl or peakr is the highest.
364 vpHistogramPeak peakl, peakr;
365 if (h.getPeaks(distance, peakl, peakr, valey) == false) {
366 std::cout << "Not a bimodal histogram..." << std::endl;
367 }
368 else {
369 vpTRACE("Bimodal histogram: valey %d-%d for peakl: %d-%d peakr: %d-%d", valey.getLevel(), valey.getValue(),
370 peakl.getLevel(), peakl.getValue(), peakr.getLevel(), peakr.getValue());
371 }
372 return EXIT_SUCCESS;
373 }
374 catch (const vpException &e) {
375 std::cout << "Catch an exception: " << e << std::endl;
376 return EXIT_FAILURE;
377 }
378}
error that can be emitted by ViSP classes.
Definition vpException.h:60
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.
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:131
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:450