Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpTutoSegmentation.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 "vpTutoSegmentation.h"
32 
33 #include <visp3/core/vpGaussRand.h>
34 
35 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
36 #ifndef DOXYGEN_SHOULD_SKIP_THIS
37 namespace tutorial
38 {
39 #ifdef ENABLE_VISP_NAMESPACE
40 using namespace VISP_NAMESPACE_NAME;
41 #endif
42 
43 void performSegmentationHSV(vpTutoCommonData &data)
44 {
45  const unsigned int height = data.m_I_orig.getHeight(), width = data.m_I_orig.getWidth();
46  vpImage<unsigned char> H(height, width);
47  vpImage<unsigned char> S(height, width);
48  vpImage<unsigned char> V(height, width);
49  vpImageConvert::RGBaToHSV(reinterpret_cast<unsigned char *>(data.m_I_orig.bitmap),
50  H.bitmap,
51  S.bitmap,
52  V.bitmap,
53  data.m_I_orig.getSize());
54 
55  vpImageTools::inRange(H.bitmap,
56  S.bitmap,
57  V.bitmap,
58  data.m_hsv_values,
59  data.m_mask.bitmap,
60  data.m_mask.getSize());
61 
62  vpImageTools::inMask(data.m_I_orig, data.m_mask, data.m_I_segmented);
63 }
64 
65 std::vector< VISP_NAMESPACE_ADDRESSING vpImagePoint > extractSkeleton(vpTutoCommonData &data)
66 {
67  const int height = data.m_mask.getHeight();
68  const int width = data.m_mask.getWidth();
69  data.m_Iskeleton.resize(height, width, 0);
70  std::vector<vpImagePoint> points;
71  // Edge thinning along the horizontal direction
72  for (int y = 0; y < height; ++y) {
73  int left = -1;
74  for (int x = 0; x < width - 1; ++x) {
75  if ((data.m_mask[y][x] > 0) && (data.m_mask[y][x + 1] > 0)) {
76  if (left < 0) {
77  left = x;
78  }
79  }
80  else if (data.m_mask[y][x] > 0) {
81  int cx = x; // Case 1 pix wide
82  if (left >= 0) {
83  // Case more than 1 pix wide
84  cx = static_cast<int>(((left + x) - 1) * 0.5f);
85  }
86  vpImagePoint pt(y, cx);
87  points.push_back(pt);
88  data.m_Iskeleton[y][cx] = 255;
89  left = -1;
90  }
91  }
92  }
93 
94  // Edge thinning along the vertical direction
95  for (int x = 0; x < width; ++x) {
96  int top = -1;
97  for (int y = 0; y < height - 1; ++y) {
98  if ((data.m_mask[y][x] > 0) && (data.m_mask[y + 1][x] > 0)) {
99  if (top < 0) {
100  top = y;
101  }
102  }
103  else if (data.m_mask[y][x] > 0) {
104  int cy = y; // Case 1 pix wide
105  if (top >= 0) {
106  cy = static_cast<int>(((top + y) - 1) * 0.5f); // Case more than 1 pix wide
107  }
108  if (data.m_Iskeleton[cy][x] == 0) {
109  vpImagePoint pt(cy, x);
110  points.push_back(pt);
111  data.m_Iskeleton[cy][x] = 255;
112  }
113  top = -1;
114  }
115  }
116  }
117  return points;
118 }
119 
120 std::vector< vpImagePoint > addSaltAndPepperNoise(const std::vector< vpImagePoint > &noisefreePts, vpTutoCommonData &data)
121 {
122  const unsigned int nbNoiseFreePts = static_cast<unsigned int>(noisefreePts.size());
123  const unsigned int nbPtsToAdd = static_cast<unsigned int>(data.m_ratioSaltPepperNoise * nbNoiseFreePts);
124  const double width = data.m_Iskeleton.getWidth();
125  const double height = data.m_Iskeleton.getHeight();
126  data.m_IskeletonNoisy = data.m_Iskeleton;
127  vpGaussRand rngX(0.1666, 0.5, static_cast<long>(vpTime::measureTimeMicros()));
128  vpGaussRand rngY(0.1666, 0.5, static_cast<long>(vpTime::measureTimeMicros() + 4224));
129  std::vector<vpImagePoint> noisyPts = noisefreePts;
130  for (unsigned int i = 0; i < nbPtsToAdd + 1; ++i) {
131  double uNormalized = rngX();
132  double vNormalized = rngY();
133  // Clamp to interval[0, 1[
134  uNormalized = std::max(uNormalized, 0.);
135  uNormalized = std::min(uNormalized, 0.99999);
136  vNormalized = std::max(vNormalized, 0.);
137  vNormalized = std::min(vNormalized, 0.99999);
138  // Scale to image size
139  double u = uNormalized * width;
140  double v = vNormalized * height;
141  // Create corresponding image point
142  vpImagePoint pt(v, u);
143  noisyPts.push_back(pt);
144  data.m_IskeletonNoisy[static_cast<int>(v)][static_cast<int>(u)] = 255;
145  }
146  return noisyPts;
147 }
148 }
149 #endif
150 #else
151 void dummy_vpTutoSegmentation() { }
152 #endif
Class for generating random number with normal probability density.
Definition: vpGaussRand.h:117
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
static int inMask(const vpImage< unsigned char > &I, const vpImage< unsigned char > &mask, vpImage< unsigned char > &I_mask)
static int inRange(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value, const vpColVector &hsv_range, unsigned char *mask, unsigned int size)
VISP_EXPORT double measureTimeMicros()