30#ifndef VP_COMMMON_DATA_H
31#define VP_COMMMON_DATA_H
35#include <visp3/core/vpConfig.h>
36#include <visp3/core/vpImage.h>
37#include <visp3/core/vpImageFilter.h>
38#include <visp3/core/vpIoTools.h>
39#include <visp3/core/vpMath.h>
40#include <visp3/gui/vpDisplayFactory.h>
41#include <visp3/io/vpVideoReader.h>
43#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
44#ifndef DOXYGEN_SHOULD_SKIP_THIS
47inline void log(std::ostream &os,
const std::string &filename,
const std::string &funName,
const std::string &arrayName,
const VISP_NAMESPACE_ADDRESSING vpArray2D<double> &array,
const unsigned int &level = 0)
49 os <<
"[" <<
filename <<
"::" << funName <<
"] ";
50 for (
unsigned int i = 0;
i <
level; ++
i) {
53 os << arrayName <<
":=" << std::endl;
54 for (
unsigned int r = 0;
r < array.getRows(); ++
r) {
55 for (
unsigned int i = 0;
i <
level; ++
i) {
59 for (
unsigned int c = 0; c < array.getCols() - 1; ++c) {
60 os << std::setprecision(3) << std::scientific << array[
r][c] <<
"\t; ";
62 os << array[
r][array.getCols() - 1] <<
"]\n";
67typedef struct vpTutoCommonData
69 static const int SOFTWARE_CONTINUE = 4221;
70 const VISP_NAMESPACE_ADDRESSING vpColor m_colorLegend = VISP_NAMESPACE_ADDRESSING
vpColor::red;
71 const VISP_NAMESPACE_ADDRESSING vpImagePoint m_ipLegend = VISP_NAMESPACE_ADDRESSING vpImagePoint(20, 20);
72 const VISP_NAMESPACE_ADDRESSING vpImagePoint m_legendOffset = VISP_NAMESPACE_ADDRESSING vpImagePoint(20, 0);
73 std::string m_seqFilename;
74 VISP_NAMESPACE_ADDRESSING vpVideoReader m_grabber;
75 std::string m_hsvFilename;
76 VISP_NAMESPACE_ADDRESSING vpColVector m_hsv_values;
78 double m_ratioSaltPepperNoise;
79 unsigned int m_degree;
82 VISP_NAMESPACE_ADDRESSING vpImage<VISP_NAMESPACE_ADDRESSING vpRGBa> m_I_orig;
83 VISP_NAMESPACE_ADDRESSING vpImage<VISP_NAMESPACE_ADDRESSING vpRGBa> m_I_segmented;
84 VISP_NAMESPACE_ADDRESSING vpImage<unsigned char> m_mask;
85 VISP_NAMESPACE_ADDRESSING vpImage<unsigned char> m_Iskeleton;
86 VISP_NAMESPACE_ADDRESSING vpImage<unsigned char> m_IskeletonNoisy;
87#if defined(VISP_HAVE_DISPLAY)
88 std::shared_ptr<VISP_NAMESPACE_ADDRESSING vpDisplay> m_displayOrig;
89 std::shared_ptr<VISP_NAMESPACE_ADDRESSING vpDisplay> m_displaySegmented;
90 std::shared_ptr<VISP_NAMESPACE_ADDRESSING vpDisplay> m_displayNoisy;
94 double m_pfMaxDistanceForLikelihood;
96 std::vector<double> m_pfRatiosAmpliMax;
101 : m_seqFilename(VISP_NAMESPACE_ADDRESSING vpIoTools::createFilePath(
"data",
"color_image_%04d.png"))
102 , m_hsvFilename(VISP_NAMESPACE_ADDRESSING vpIoTools::createFilePath(
"calib",
"hsv-thresholds.yml"))
104 , m_ratioSaltPepperNoise(0.15)
106 , m_pfMaxDistanceForLikelihood(40)
108 , m_pfRatiosAmpliMax({ 0.25, 0.25, 0.25 })
118 inline void printHelp(
const char *softName)
120 std::cout <<
"\nSYNOPSIS " << std::endl
122 <<
" [--video <input video>] [--hsv-thresholds <filename.yml>] [--noise <ratio>]" << std::endl
123 <<
" [--degree <uint>]" << std::endl
124 <<
" [--max-distance-likelihood <double>] [-N, --nb-particles <uint>] [--seed <int>] [--nb-threads <int>] [--state-noise-ratio <ratio>]" << std::endl
127 std::cout <<
"\nOPTIONS " << std::endl
128 <<
" [General params]" << std::endl
129 <<
" --video <input video>" << std::endl
130 <<
" Name of the input video filename." << std::endl
131 <<
" If name is set to \"generate-simulated\" a simulated image is generated." << std::endl
132 <<
" Example: --video " << this->m_seqFilename << std::endl
134 <<
" --hsv-thresholds <filename.yaml>" << std::endl
135 <<
" Path to a yaml filename that contains H <min,max>, S <min,max>, V <min,max> threshold values." << std::endl
136 <<
" For an example, have a look to the file \"" << this->m_hsvFilename <<
"\"" << std::endl
138 <<
" --noise <ratio, [0; 1.[ >" << std::endl
139 <<
" Ratio of noisy points added to the image resulting from the skeletonization of the segmented image, to simulate sensor noise." << std::endl
140 <<
" Default = " << this->m_ratioSaltPepperNoise << std::endl
142 <<
" --degree <uint>" << std::endl
143 <<
" Choose the degree of the polynomials to use." << std::endl
144 <<
" Default = " << this->m_degree << std::endl
147 <<
" [PF params]" << std::endl
148 <<
" --max-distance-likelihood" << std::endl
149 <<
" Maximum mean square distance between a particle with the measurements." << std::endl
150 <<
" Above this value, the likelihood of the particle is 0." << std::endl
151 <<
" NOTE: M-estimation is used to make the likelihood function robust against outliers." << std::endl
152 <<
" Default: " << m_pfMaxDistanceForLikelihood << std::endl
154 <<
" -N, --nb-particles" << std::endl
155 <<
" Number of particles of the Particle Filter." << std::endl
156 <<
" Default: " << m_pfN << std::endl
158 <<
" --seed" << std::endl
159 <<
" Seed to initialize the Particle Filter." << std::endl
160 <<
" Use a negative value makes to use the current timestamp instead." << std::endl
161 <<
" Default: " << m_pfSeed << std::endl
163 <<
" --nb-threads" << std::endl
164 <<
" Set the number of threads to use in the Particle Filter (only if OpenMP is available)." << std::endl
165 <<
" Use a negative value to use the maximum number of threads instead." << std::endl
166 <<
" Default: " << m_pfNbThreads << std::endl
168 <<
" --state-noise-ratio <ratio>" << std::endl
169 <<
" Ratio of the initial guess of the curve coefficients to use as maximal amplitude of the noise added to the particles." << std::endl
170 <<
" Default: " << m_pfRatiosAmpliMax[0] << std::endl
171 <<
" --help, -h" << std::endl
172 <<
" Display this helper message." << std::endl
184 inline int init(
const int &argc,
const char *argv[])
189 std::string argname(argv[i]);
190 if ((argname == std::string(
"--video")) && ((i + 1) < argc)) {
192 m_seqFilename = std::string(argv[i]);
194 else if ((argname == std::string(
"--hsv-thresholds")) && ((i + 1) < argc)) {
196 m_hsvFilename = std::string(argv[i]);
198 else if ((argname ==
"--noise") && ((i + 1) < argc)) {
200 m_ratioSaltPepperNoise = std::atof(argv[i]);
202 else if ((argname == std::string(
"--degree")) && ((i + 1) < argc)) {
204 m_degree = std::atoi(argv[i]);
206 else if ((argname ==
"--max-distance-likelihood") && ((i+1) < argc)) {
208 m_pfMaxDistanceForLikelihood = std::atof(argv[i]);
210 else if (((argname ==
"-N") || (argname ==
"--nb-particles")) && ((i+1) < argc)) {
212 m_pfN = std::atoi(argv[i]);
214 else if ((argname ==
"--seed") && ((i+1) < argc)) {
216 m_pfSeed = std::atoi(argv[i]);
218 else if ((argname ==
"--nb-threads") && ((i+1) < argc)) {
220 m_pfNbThreads = std::atoi(argv[i]);
222 else if ((argname ==
"--state-noise-ratio") && ((i+1) < argc)) {
224 m_pfRatiosAmpliMax[0] = std::atof(argv[i]);
226 else if ((argname == std::string(
"-h")) || (argname == std::string(
"--help"))) {
227 vpTutoCommonData helpPrinter;
228 helpPrinter.printHelp(argv[0]);
232 std::cerr <<
"Unknown argument \"" << argname <<
"\"" << std::endl;
239 m_pfRatiosAmpliMax.resize(m_degree, m_pfRatiosAmpliMax[0]);
243 std::cout <<
"Load HSV threshold values from " << m_hsvFilename << std::endl;
244 std::cout <<
"HSV low/high values: " << m_hsv_values.t() << std::endl;
247 std::cout <<
"ERROR: unable to load HSV thresholds values from " << m_hsvFilename << std::endl;
253 m_grabber.setFileName(m_seqFilename);
254 m_grabber.open(m_I_orig);
256 catch (
const VISP_NAMESPACE_ADDRESSING vpException &e) {
257 std::cout <<
e.getStringMessage() << std::endl;
261 m_I_segmented.resize(m_I_orig.getHeight(), m_I_orig.getWidth());
262 m_mask.resize(m_I_orig.getHeight(), m_I_orig.getWidth());
263 m_Iskeleton.resize(m_I_orig.getHeight(), m_I_orig.getWidth());
264 m_IskeletonNoisy.resize(m_I_orig.getHeight(), m_I_orig.getWidth());
267#if defined(VISP_HAVE_DISPLAY)
268 const int horOffset = 20, vertOffset = 25;
269 std::string skeletonTitle(
"Skeletonized image (");
270 skeletonTitle += (VISP_NAMESPACE_ADDRESSING
vpMath::equal(m_ratioSaltPepperNoise, 0.) ?
"without" : std::to_string(
static_cast<unsigned int>(m_ratioSaltPepperNoise * 100.)) +
"%");
271 skeletonTitle +=
" noise)";
273 m_displaySegmented = VISP_NAMESPACE_ADDRESSING
vpDisplayFactory::createDisplay(m_I_segmented, 2 * horOffset + m_I_orig.getWidth(), vertOffset,
"Segmented image");
274 m_displayNoisy = VISP_NAMESPACE_ADDRESSING
vpDisplayFactory::createDisplay(m_IskeletonNoisy, 2 * horOffset + m_I_orig.getWidth(), 2 * vertOffset + m_I_orig.getHeight(), skeletonTitle);
276 return SOFTWARE_CONTINUE;
279#ifdef VISP_HAVE_DISPLAY
281 void displayLegend(
const VISP_NAMESPACE_ADDRESSING vpImage<T> &I)
283 VISP_NAMESPACE_ADDRESSING vpImagePoint ip(20, 20);
284 VISP_NAMESPACE_ADDRESSING vpImagePoint offset(20, 0);
288 VISP_NAMESPACE_ADDRESSING
vpDisplay::displayText(I, ip + offset, std::string(
"Middle click to switch to ") + (m_stepbystep ? std::string(
"video mode") : std::string(
"step-by-step mode")), VISP_NAMESPACE_ADDRESSING
vpColor::red);
293 bool manageClicks(
const VISP_NAMESPACE_ADDRESSING vpImage<T> &I,
bool &stepbystep)
295 VISP_NAMESPACE_ADDRESSING vpImagePoint ip;
302 stepbystep = stepbystep ^
true;
static bool loadYAML(const std::string &filename, vpArray2D< double > &A, char *header=nullptr)
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
static bool equal(double x, double y, double threshold=0.001)
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.