30#ifndef VP_RB_TRACKER_TUTORIAL_HELPER_H
31#define VP_RB_TRACKER_TUTORIAL_HELPER_H
42#include <visp3/core/vpImage.h>
43#include <visp3/core/vpImageFilter.h>
44#include <visp3/core/vpImageConvert.h>
45#include <visp3/core/vpImageTools.h>
46#include <visp3/core/vpIoTools.h>
47#include <visp3/core/vpDisplay.h>
48#include <visp3/core/vpTime.h>
49#include <visp3/gui/vpDisplayFactory.h>
51#include <visp3/io/vpImageIo.h>
52#include <visp3/io/vpJsonArgumentParser.h>
53#include <visp3/io/vpVideoWriter.h>
55#include <visp3/gui/vpPlot.h>
57#include <visp3/rbt/vpRBTracker.h>
58#include <visp3/rbt/vpObjectMask.h>
59#include <visp3/rbt/vpRBDriftDetector.h>
61#include "pStatClient.h"
63#ifndef DOXYGEN_SHOULD_SKIP_THIS
64namespace vpRBTrackerTutorial
67#ifdef ENABLE_VISP_NAMESPACE
68using namespace VISP_NAMESPACE_NAME;
78 BaseArguments() : trackerConfiguration(
""), maxDepthDisplay(1.f), verbose(false), display(true), debugDisplay(false), enableRenderProfiling(false) { }
80#if defined(VISP_HAVE_NLOHMANN_JSON)
81 void registerArguments(vpJsonArgumentParser &parser)
84 .addArgument(
"--tracker", trackerConfiguration,
false,
"Path to the JSON file containing the tracker")
85 .addArgument(
"--object",
object,
false,
"Name of the object to track. Used to potentially fetch the init file")
86 .addArgument(
"--init-file", initFile,
false,
"Path to the JSON file containing the 2D/3D correspondences for initialization by click")
87 .addArgument(
"--pose", inlineInit,
false,
"Initial pose of the object in the camera frame.")
88 .addArgument(
"--max-depth-display", maxDepthDisplay,
false,
"Maximum depth value, used to scale the depth display")
89 .addFlag(
"--verbose", verbose,
"Log additional information in console")
90 .addFlag(
"--no-display", display,
"Disable display windows")
91 .addFlag(
"--debug-display", debugDisplay,
"Enable additional displays from the renderer")
92 .addFlag(
"--profile", enableRenderProfiling,
"Enable the use of Pstats to profile rendering times");
96 void postProcessArguments()
98 if (trackerConfiguration.empty()) {
101 if (
object.empty()) {
109 if (initFile.empty()) {
113 if (!display && inlineInit.empty()) {
114 throw vpException(
vpException::badValue,
"Cannot disable displays without specifying the initial pose");
116 if (inlineInit.size() > 0) {
117 if (inlineInit.size() != 6) {
118 throw vpException(
vpException::dimensionError,
"Inline pose initialization expected to have 6 values (tx, ty, tz, tux, tuy, tuz)");
120 for (
unsigned int i = 0;
i < 6; ++
i) {
121 std::cout <<
"inline i = " << inlineInit[
i] << std::endl;
123 cMoInit = vpHomogeneousMatrix(inlineInit[0], inlineInit[1], inlineInit[2], inlineInit[3], inlineInit[4], inlineInit[5]);
129 return !inlineInit.empty();
132 std::string trackerConfiguration;
134 std::string modelPath;
135 std::string initFile;
136 std::vector<double> inlineInit;
137 float maxDepthDisplay;
138 vpHomogeneousMatrix cMoInit;
142 bool enableRenderProfiling;
154class vpRBExperimentLogger
157 vpRBExperimentLogger() : enabled(false), videoEnabled(false), framerate(30)
160#if defined(VISP_HAVE_NLOHMANN_JSON)
161 void registerArguments(vpJsonArgumentParser &parser)
164 .addFlag(
"--save", enabled,
"Whether to save experiment data")
165 .addArgument(
"--save-path", folder,
false,
"Where to save the experiment log. The folder should not exist.")
166 .addFlag(
"--save-video", videoEnabled,
"Whether to save the video")
167 .addArgument(
"--video-framerate", framerate,
false,
"Output video framerate");
175 if (folder.empty()) {
180#ifdef VISP_HAVE_OPENCV
181 videoWriter.setFramerate(framerate);
182 videoWriter.setCodec(cv::VideoWriter::fourcc(
'P',
'I',
'M',
'1'));
189 void logFrame(
const vpRBTracker &
190#
if defined(VISP_HAVE_NLOHMANN_JSON)
193 ,
unsigned int iter,
const vpImage<unsigned char> &I,
const vpImage<vpRGBa> &IRGB,
194 const vpImage<unsigned char> &Idepth,
const vpImage<unsigned char> &Imask)
201 Iout.resize(
IRGB.getHeight() * 2,
IRGB.getWidth() * 2);
207#ifdef VISP_HAVE_OPENMP
208#pragma omp parallel for
210 for (
int i = 0; i < static_cast<int>(
IRGB.getHeight()); ++
i) {
211 memcpy(Iout[i], IgrayOverlay[i],
IRGB.getWidth() *
sizeof(vpRGBa));
212 memcpy(Iout[i] +
IRGB.getWidth(), IColOverlay[i],
IRGB.getWidth() *
sizeof(vpRGBa));
213 memcpy(Iout[i +
IRGB.getHeight()], IdepthOverlay[i],
IRGB.getWidth() *
sizeof(vpRGBa));
214 memcpy(Iout[i +
IRGB.getHeight()] +
IRGB.getWidth(), ImaskOverlay[i],
IRGB.getWidth() *
sizeof(vpRGBa));
218 videoWriter.open(Iout);
221 videoWriter.saveFrame(Iout);
224#if defined(VISP_HAVE_NLOHMANN_JSON)
225 nlohmann::json iterLog;
226 vpHomogeneousMatrix
cMo;
228 iterLog[
"cMo"] =
cMo;
230 log.push_back(iterLog);
240#if defined(VISP_HAVE_NLOHMANN_JSON)
242 f << log.dump(2) << std::endl;
251 vpImage<vpRGBa> IColOverlay;
252 vpImage<vpRGBa> IgrayOverlay;
253 vpImage<vpRGBa> IdepthOverlay;
254 vpImage<vpRGBa> ImaskOverlay;
255 vpImage<vpRGBa> Iout;
258 unsigned int framerate;
259 vpVideoWriter videoWriter;
261#if defined(VISP_HAVE_NLOHMANN_JSON)
270class vpRBExperimentPlotter
274 vpRBExperimentPlotter() : enabled(false), plotPose(false), plotPose3d(false), plotDivergenceMetrics(false), plotCovariance(false) { }
276#if defined(VISP_HAVE_NLOHMANN_JSON)
277 void registerArguments(vpJsonArgumentParser &parser)
280 .addFlag(
"--plot-pose", plotPose,
"Plot the pose of the object in the camera frame")
281 .addFlag(
"--plot-position", plotPose3d,
"Plot the position of the object in a 3d figure")
282 .addFlag(
"--plot-divergence", plotDivergenceMetrics,
"Plot the metrics associated to the divergence threshold computation")
283 .addFlag(
"--plot-cov", plotCovariance,
"Plot the pose covariance trace for each feature");
287 void postProcessArguments(
bool displayEnabled)
289 enabled = plotPose || plotDivergenceMetrics || plotPose3d || plotCovariance;
290 if (enabled && !displayEnabled) {
295 void init(std::vector<std::shared_ptr<vpDisplay>> &displays)
300 int ypos = 0, xpos = 0;
301 for (std::shared_ptr<vpDisplay> &display : displays) {
302 ypos = std::min(ypos, display->getWindowYPosition());
303 xpos = std::max(xpos, display->getWindowXPosition() +
static_cast<int>(display->getWidth()));
306 numPlots =
static_cast<int>(plotPose) +
static_cast<int>(plotDivergenceMetrics) +
static_cast<int>(plotPose3d) +
static_cast<int>(plotCovariance);
307 plotter.init(numPlots, 600, 800, xpos, ypos,
"Plot");
308 unsigned int plotIndex = 0;
310 plotter.initGraph(plotIndex, 6);
311 plotter.setTitle(plotIndex,
"cMo");
312 std::vector<std::string> legends = {
313 "tx",
"ty",
"tz",
"tux",
"tuy",
"tuz"
315 for (
unsigned int i = 0;
i < 6; ++
i) {
316 plotter.setLegend(plotIndex, i, legends[i]);
318 plotter.setGraphThickness(plotIndex, 2);
322 plotter.initGraph(plotIndex, 1);
323 plotter.setTitle(plotIndex,
"3D object position");
324 plotter.setGraphThickness(plotIndex, 2);
328 if (plotDivergenceMetrics) {
329 plotter.initGraph(plotIndex, 1);
330 plotter.initRange(plotIndex, 0.0, 1.0, 0.0, 1.0);
331 plotter.setTitle(plotIndex,
"Divergence");
334 if (plotCovariance) {
335 plotter.initGraph(plotIndex, 2);
336 plotter.setLegend(plotIndex, 0,
"Translation trace standard deviation (cm)");
337 plotter.setLegend(plotIndex, 1,
"Rotation trace standard deviation (deg)");
339 plotter.setTitle(plotIndex,
"Covariance");
344 void plot(
const vpRBTracker &tracker,
double time)
349 unsigned int plotIndex = 0;
351 vpHomogeneousMatrix
cMo;
353 plotter.plot(plotIndex, time, vpPoseVector(cMo));
357 vpHomogeneousMatrix
cMo;
359 vpTranslationVector
t =
cMo.getTranslationVector();
360 plotter.plot(plotIndex, 0, t[0], t[1], t[2]);
363 if (plotDivergenceMetrics) {
364 const std::shared_ptr<const vpRBDriftDetector> driftDetector =
tracker.getDriftDetector();
365 double metric = driftDetector ? driftDetector->getScore() : 0.0;
366 plotter.plot(plotIndex, 0, time, metric);
369 if (plotCovariance) {
370 vpMatrix cov =
tracker.getCovariance();
371 double traceTranslation = 0.0, traceRotation = 0.0;
372 for (
unsigned int i = 0;
i < 3; ++
i) {
373 traceTranslation += cov[
i][
i];
374 traceRotation += cov[
i + 3][
i + 3];
376 traceTranslation = sqrt(traceTranslation) * 100;
379 plotter.plot(plotIndex, 0, time, traceTranslation);
380 plotter.plot(plotIndex, 1, time, traceRotation);
389 bool plotDivergenceMetrics;
405std::vector<std::shared_ptr<vpDisplay>> createDisplays(
406 vpImage<unsigned char> &Id, vpImage<vpRGBa> &Icol,
407 vpImage<unsigned char> &depthDisplay, vpImage<unsigned char> &probaDisplay)
415 "Depth", depthDisplay,
416 "Proba mask", probaDisplay
420std::vector<std::shared_ptr<vpDisplay>> createDisplays(
421 vpImage<unsigned char> &Id, vpImage<vpRGBa> &Icol, vpImage<unsigned char> &probaDisplay)
429 "Proba mask", probaDisplay
436void enableRendererProfiling()
438 if (PStatClient::is_connected()) {
439 PStatClient::disconnect();
442 std::string host =
"";
444 if (!PStatClient::connect(host, port)) {
445 std::cout <<
"Could not connect to PStat server." << std::endl;
455void displayNormals(
const vpImage<vpRGBf> &normalsImage, vpImage<vpRGBa> &normalDisplayImage)
457#ifdef VISP_HAVE_OPENMP
458#pragma omp parallel for
460 for (
int i = 0; i < static_cast<int>(normalsImage.
getSize()); ++
i) {
461 normalDisplayImage.
bitmap[
i].R =
static_cast<unsigned char>((normalsImage.
bitmap[
i].R + 1.0) * 127.5f);
462 normalDisplayImage.
bitmap[
i].G =
static_cast<unsigned char>((normalsImage.
bitmap[
i].G + 1.0) * 127.5f);
463 normalDisplayImage.
bitmap[
i].B =
static_cast<unsigned char>((normalsImage.
bitmap[
i].B + 1.0) * 127.5f);
479void displayCanny(
const vpImage<float> &cannyRawData,
480 vpImage<unsigned char> &canny,
const vpImage<unsigned char> &valid)
482#ifdef VISP_HAVE_OPENMP
483#pragma omp parallel for
485 for (
int i = 0; i < static_cast<int>(cannyRawData.
getSize()); ++
i) {
492 for (
unsigned int i = 0;
i < canny.
getHeight();
i += 4) {
493 for (
unsigned int j = 0;
j < canny.
getWidth();
j += 4) {
494 if (!valid[i][j])
continue;
495 float angle = cannyRawData[
i][
j];
496 unsigned x =
j + 10 * cos(angle);
497 unsigned y =
i + 10 * sin(angle);
static const vpColor green
static void display(const vpImage< unsigned char > &I)
static void getImage(const vpImage< unsigned char > &Is, vpImage< vpRGBa > &Id)
static void flush(const vpImage< unsigned char > &I)
static void displayArrow(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
@ badValue
Used to indicate that a value is not in the allowed range.
@ dimensionError
Bad dimension.
unsigned int getWidth() const
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
static double deg(double rad)
std::vector< std::shared_ptr< vpDisplay > > makeDisplayGrid(unsigned int rows, unsigned int cols, unsigned int startX, unsigned int startY, unsigned int paddingX, unsigned int paddingY, Args &... args)
Create a grid of displays, given a set of images. All the displays will be initialized in the correct...