Visual Servoing Platform  version 3.6.1 under development (2025-03-16)
vpColorHistogramMask.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 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 
39 BEGIN_VISP_NAMESPACE
40 
41 vpColorHistogramMask::vpColorHistogramMask() : m_computeOnBBOnly(false) { }
42 
44  const vpRBFeatureTrackerInput &previousFrame,
45  vpImage<float> &mask)
46 {
47  // Prefer the last frame:
48  // we have updated the render to match the pose so we should get better object and background histogram separation.
49  const vpImage<vpRGBa> &rgb = previousFrame.IRGB.getSize() == 0 ? frame.IRGB : previousFrame.IRGB;
50 
51  const int height = static_cast<int>(rgb.getHeight()), width = static_cast<int>(rgb.getWidth());
52  m_mask.resize(height, width, false);
53  const vpRect renderBB = frame.renders.boundingBox;
54  const int top = static_cast<int>(renderBB.getTop());
55  const int left = static_cast<int>(renderBB.getLeft());
56  const int bottom = std::min(height - 1, static_cast<int>(renderBB.getBottom()));
57  const int right = std::min(width - 1, static_cast<int>(renderBB.getRight()));
58 
59  const vpImage<float> &renderDepth = frame.renders.depth;
60  const vpImage<float> &depth = previousFrame.depth.getSize() == 0 ? frame.depth : previousFrame.depth;
61  if (depth.getSize() > 0 && m_depthErrorTolerance > 0.f) {
62  for (unsigned int i = top; i <= static_cast<unsigned int>(bottom); ++i) {
63  for (unsigned int j = left; j <= static_cast<unsigned int>(right); ++j) {
64  m_mask[i][j] = renderDepth[i][j] > 0.f && fabs(renderDepth[i][j] - depth[i][j]) <= m_depthErrorTolerance;
65  }
66  }
67  }
68  else {
69  for (unsigned int i = top; i <= static_cast<unsigned int>(bottom); ++i) {
70  for (unsigned int j = left; j <= static_cast<unsigned int>(right); ++j) {
71  m_mask[i][j] = renderDepth[i][j] > 0.f;
72  }
73  }
74  }
75  vpColorHistogram::computeSplitHistograms(rgb, m_mask, renderBB, m_histObjectFrame, m_histBackgroundFrame);
76 
77  const float pObject = static_cast<float>(m_histObjectFrame.getNumPixels()) / static_cast<float>(m_mask.getSize());
78  const float pBackground = 1.f - pObject;
79  {
80  {
81  if (pObject != 0.f) {
82  m_histObject.merge(m_histObjectFrame, m_objectUpdateRate);
83  }
84  if (m_computeOnBBOnly) {
85  m_histObject.computeProbas(frame.IRGB, m_probaObject, frame.renders.boundingBox);
86  }
87  else {
88  m_histObject.computeProbas(frame.IRGB, m_probaObject);
89  }
90  }
91  {
92  if (pBackground != 0.f) {
93  m_histBackground.merge(m_histBackgroundFrame, m_backgroundUpdateRate);
94  }
95  if (m_computeOnBBOnly) {
96  m_histBackground.computeProbas(frame.IRGB, m_probaBackground, frame.renders.boundingBox);
97  }
98  else {
99  m_histBackground.computeProbas(frame.IRGB, m_probaBackground);
100  }
101  }
102  }
103 
104  if (m_computeOnBBOnly) {
105  mask.resize(height, width, 0.f);
106 #pragma omp parallel for
107  for (unsigned int i = top; i <= static_cast<unsigned int>(bottom); ++i) {
108  for (unsigned int j = left; j <= static_cast<unsigned int>(right); ++j) {
109  const float poPix = m_probaObject[i][j];
110  const float pbPix = m_probaBackground[i][j];
111 
112  float denom = (pObject * poPix + pBackground * pbPix);
113  mask[i][j] = (denom > 0.f) * std::max(0.f, std::min(1.f, (poPix / denom)));
114  m_mask[i][j] = renderDepth[i][j] > 0.f && fabs(renderDepth[i][j] - depth[i][j]) <= m_depthErrorTolerance;
115  }
116  }
117  }
118  else {
119  mask.resize(height, width);
120  for (unsigned int i = 0; i < mask.getSize(); ++i) {
121  // float poPix = m_histObject.probability(frame.IRGB.bitmap[i]);
122  // float pbPix = m_histBackground.probability(frame.IRGB.bitmap[i]);
123  const float poPix = m_probaObject.bitmap[i];
124  const float pbPix = m_probaBackground.bitmap[i];
125 
126  float denom = (pObject * poPix + pBackground * pbPix);
127  mask.bitmap[i] = (denom > 0.f) * std::max(0.f, std::min(1.f, (poPix / denom)));
128  }
129 
130  }
131 
132 }
133 
134 #if defined(VISP_HAVE_NLOHMANN_JSON)
135 void vpColorHistogramMask::loadJsonConfiguration(const nlohmann::json &json)
136 {
137  setBinNumber(json.at("bins"));
138  m_backgroundUpdateRate = json.at("backgroundUpdateRate");
139  m_objectUpdateRate = json.at("objectUpdateRate");
140  m_depthErrorTolerance = json.at("maxDepthError");
141  m_computeOnBBOnly = json.value("computeOnlyOnBoundingBox", m_computeOnBBOnly);
142 }
143 #endif
144 
145 END_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
unsigned int getNumPixels() const
static void computeSplitHistograms(const vpImage< vpRGBa > &image, const vpImage< bool > &mask, vpColorHistogram &inMask, vpColorHistogram &outsideMask)
void computeProbas(const vpImage< vpRGBa > &image, vpImage< float > &proba) const
void merge(const vpColorHistogram &other, float alpha)
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
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
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)