Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpColorHistogramMask.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
31#include <visp3/rbt/vpColorHistogramMask.h>
32
33#include <visp3/rbt/vpRBFeatureTracker.h>
34
35#if defined(VISP_HAVE_NLOHMANN_JSON)
36#include VISP_NLOHMANN_JSON(json.hpp)
37#endif
38
40
42{
43public:
45 {
46 unsigned int N = object.getBinNumber();
47 m_probas.resize(N * N * N);
48 unsigned int increment = 256 / N;
49 unsigned int half = increment / 2;
50 vpRGBa c;
51 unsigned int index = 0;
52 for (unsigned int r = half; r < 256; r += increment) {
53 c.R = r;
54 for (unsigned int g = half; g < 256; g += increment) {
55 c.G = g;
56 for (unsigned int b = half; b < 256; b += increment) {
57 c.B = b;
58 const float pbg = bg.probability(c);
59 const float pObject = object.probability(c);
60 if (pbg == 0.f) {
61 m_probas[index] = pObject > 0.f ? 1.f : 0.f;
62 }
63 else {
64 float logOdds = log(pObject / pbg);
65 const float score = 1 / (1 + exp(-logOdds));
66 m_probas[index] = score;
67 }
68 ++index;
69
70 }
71 }
72 }
73
74 }
75
76 float operator()(unsigned int colorIndex)
77 {
78 return m_probas[colorIndex];
79 }
80
81private:
82 std::vector<float> m_probas;
83};
84
85vpColorHistogramMask::vpColorHistogramMask() : m_depthErrorTolerance(0.01f), m_objectUpdateRate(0.1f), m_backgroundUpdateRate(0.1f), m_threshold(2.f), m_computeOnBBOnly(false) { }
86
88 const vpRBFeatureTrackerInput &previousFrame,
89 vpImage<float> &mask)
90{
91 // Prefer the last frame:
92 // we have updated the render to match the pose so we should get better object and background histogram separation.
93 const vpImage<vpRGBa> &rgb = previousFrame.IRGB.getSize() == 0 ? frame.IRGB : previousFrame.IRGB;
94
95 const int height = static_cast<int>(rgb.getHeight()), width = static_cast<int>(rgb.getWidth());
96 m_mask.resize(height, width, false);
97 const vpRect renderBB = frame.renders.boundingBox;
98 const int top = static_cast<int>(renderBB.getTop());
99 const int left = static_cast<int>(renderBB.getLeft());
100 const int bottom = std::min(height - 1, static_cast<int>(renderBB.getBottom()));
101 const int right = std::min(width - 1, static_cast<int>(renderBB.getRight()));
102
103 const vpImage<float> &renderDepth = frame.renders.depth;
104 const vpImage<float> &depth = previousFrame.depth.getSize() == 0 ? frame.depth : previousFrame.depth;
105 if (depth.getSize() > 0 && m_depthErrorTolerance > 0.f) {
106#ifdef VISP_HAVE_OPENMP
107#pragma omp parallel for
108#endif
109 for (int i = top; i <= bottom; ++i) {
110 for (unsigned int j = left; j <= static_cast<unsigned int>(right); ++j) {
111 m_mask[i][j] = renderDepth[i][j] > 0.f && (depth[i][j] > 0.f && fabs(renderDepth[i][j] - depth[i][j]) <= m_depthErrorTolerance);
112 }
113 }
114 }
115 else {
116#ifdef VISP_HAVE_OPENMP
117#pragma omp parallel for
118#endif
119 for (int i = top; i <= bottom; ++i) {
120 for (unsigned int j = left; j <= static_cast<unsigned int>(right); ++j) {
121 m_mask[i][j] = renderDepth[i][j] > 0.f;
122 }
123 }
124 }
125 vpColorHistogram::computeSplitHistograms(rgb, m_mask, renderBB, m_histObjectFrame, m_histBackgroundFrame);
126 const float numPxTotal = static_cast<float>(m_histObjectFrame.getNumPixels() + m_histBackgroundFrame.getNumPixels());
127
128 const float pObject = static_cast<float>(m_histObjectFrame.getNumPixels()) / numPxTotal;
129 const float pBackground = static_cast<float>(m_histBackgroundFrame.getNumPixels()) / numPxTotal;
130 {
131 {
132 if (pObject != 0.f) {
133 m_histObject.merge(m_histObjectFrame, m_objectUpdateRate);
134 }
135 }
136 {
137 if (pBackground != 0.f) {
138 m_histBackground.merge(m_histBackgroundFrame, m_backgroundUpdateRate);
139 }
140 }
141 }
142 vpProbaComputer probas(m_histObject, m_histBackground);
143
144 if (m_computeOnBBOnly) {
145 mask.resize(height, width, 0.f);
146#ifdef VISP_HAVE_OPENMP
147#pragma omp parallel for
148#endif
149 for (int i = top; i <= bottom; ++i) {
150 for (int j = left; j <= right; ++j) {
151 unsigned int index = m_histObject.colorToIndex(frame.IRGB[i][j]);
152 mask[i][j] = probas(index);
153 }
154 }
155
156 }
157 else {
158 mask.resize(height, width);
159#ifdef VISP_HAVE_OPENMP
160#pragma omp parallel for
161#endif
162 for (int i = 0; i < static_cast<int>(mask.getSize()); ++i) {
163 unsigned int index = m_histObject.colorToIndex(frame.IRGB.bitmap[i]);
164 mask.bitmap[i] = probas(index);
165 }
166 // if (maxValue > 0.0) {
167 // for (unsigned int i = 0; i < mask.getSize(); ++i) {
168 // mask.bitmap[i] /= maxValue;
169 // }
170 // }
171 }
172}
173
174#if defined(VISP_HAVE_NLOHMANN_JSON)
175void vpColorHistogramMask::loadJsonConfiguration(const nlohmann::json &json)
176{
177 setBinNumber(json.at("bins"));
178 m_backgroundUpdateRate = json.at("backgroundUpdateRate");
179 m_objectUpdateRate = json.at("objectUpdateRate");
180 m_depthErrorTolerance = json.at("maxDepthError");
181 m_computeOnBBOnly = json.value("computeOnlyOnBoundingBox", m_computeOnBBOnly);
182 m_threshold = json.value("likelihoodRatioThreshold", m_threshold);
183}
184#endif
185
186END_VISP_NAMESPACE
void loadJsonConfiguration(const nlohmann::json &json) VP_OVERRIDE
void setBinNumber(unsigned int N)
void updateMask(const vpRBFeatureTrackerInput &frame, const vpRBFeatureTrackerInput &previousFrame, vpImage< float > &mask) VP_OVERRIDE
Histogram representation of an RGB color distribution In this representation, probabilities are store...
double probability(const vpRGBa &color) const
Get the probability of an RGB color according to this histogram.
static void computeSplitHistograms(const vpImage< vpRGBa > &image, const vpImage< bool > &mask, vpColorHistogram &inMask, vpColorHistogram &outsideMask)
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getSize() const
Definition vpImage.h:221
Type * bitmap
points toward the bitmap
Definition vpImage.h:135
unsigned int getHeight() const
Definition vpImage.h:181
vpProbaComputer(const vpColorHistogram &object, const vpColorHistogram &bg)
float operator()(unsigned int colorIndex)
All the data related to a single tracking frame. This contains both the input data (from a real camer...
vpImage< vpRGBa > IRGB
Image luminance.
vpImage< float > depth
RGB image, 0 sized if RGB is not available.
vpRBRenderData renders
camera parameters
unsigned char B
Blue component.
Definition vpRGBa.h:327
unsigned char R
Red component.
Definition vpRGBa.h:325
unsigned char G
Green component.
Definition vpRGBa.h:326
Defines a rectangle in the plane.
Definition vpRect.h:79
double getLeft() const
Definition vpRect.h:173
double getRight() const
Definition vpRect.h:179
double getBottom() const
Definition vpRect.h:97
double getTop() const
Definition vpRect.h:192
vpImage< float > depth
Image containing the per-pixel normal vector (RGB, in object space).