Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
hsvUtils.h
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 * Description:
31 * HSV color scale utils.
32 */
33
34#ifndef HSV_UTILS_H
35#define HSV_UTILS_H
36
37#include <iostream>
38#include <map>
39
40#include <visp3/core/vpColorGetter.h>
41#include <visp3/core/vpImage.h>
42
43#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
44#include <type_traits>
45
47#ifndef DOXYGEN_SHOULD_SKIP_THIS
48namespace vpHSVTests
49{
58template<typename T>
59inline typename std::enable_if<std::is_arithmetic<T>::value, double>::type error(const T &a, const T &b)
60{
61 return std::abs(a - b);
62}
63
73template<typename Tp, int I = 0>
74inline typename std::enable_if<I == Tp::nbChannels, double>::type error(const Tp &t1, const Tp &t2)
75{
76 (void)t1;
77 (void)t2;
78 return 0.;
79}
80
90template<typename Tp, int I = 0>
91inline typename std::enable_if<I < Tp::nbChannels, double>::type error(const Tp &t1, const Tp &t2)
92{
93 const double &val1 = vpColorGetter<I>::get(t1);
94 const double &val2 = vpColorGetter<I>::get(t2);
95 const double den = 1. / Tp::nbChannels;
96 double err = den * std::abs(val1 - val2) + error<Tp, I + 1>(t1, t2);
97 return err;
98}
99
110template<typename T>
111bool areAlmostEqual(const vpImage<T> &I1, const std::string &nameI1, const vpImage<T> &I2, const std::string &nameI2, const double &thresh = 1e-3)
112{
113 bool areEqual = true;
114 if (I1.getWidth() != I2.getWidth()) {
115 std::cerr << "ERROR: Image width differ." << std::endl;
116 }
117
118 if (I1.getHeight() != I2.getHeight()) {
119 std::cerr << "ERROR: Image height differ." << std::endl;
120 }
121
122 unsigned int width = I1.getWidth(), height = I1.getHeight();
123 for (unsigned int r = 0; (r < height) && areEqual; ++r) {
124 for (unsigned int c = 0; (c < width) && areEqual; ++c) {
125 double err = error(I1[r][c], I2[r][c]);
126 if (err > thresh) {
127 std::cerr << "ERROR: Error (" << err << ") > thresh (" << thresh << ")" << std::endl;
128 std::cerr << "\t" << nameI1 << "[" << r << "][" << c << "] = (" << I1[r][c] << ") , " << nameI2 << "[" << r << "][" << c << "] = (" << I2[r][c] << ")" << std::endl;
129 areEqual = false;
130 }
131 }
132 }
133 return areEqual;
134}
135
143template<typename ArithmeticType, bool useFullScale>
144void print(const vpImage<vpHSV<ArithmeticType, useFullScale>> &I, const std::string &name)
145{
146 std::cout << name << " = " << std::endl;
147 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
148 for (unsigned int r = 0; r < nbRows; ++r) {
149 for (unsigned int c = 0; c < nbCols; ++c) {
150 std::string character;
151 if (vpMath::nul(I[r][c].H, 1e-3)) {
152 character = '0';
153 }
154 else {
155 double val = static_cast<double>(I[r][c].H);
156 if (val > 0 && val < 1.) {
157 val *= 10.;
158 }
159 character = std::to_string(static_cast<unsigned int>(val));
160 }
161 std::cout << character << " ";
162 }
163 std::cout << std::endl;
164 }
165 std::cout << std::endl;
166}
167
174template<typename ArithmeticType>
175void print(const vpImage<ArithmeticType> &I, const std::string &name)
176{
177 std::cout << name << " = " << std::endl;
178 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
179 for (unsigned int r = 0; r < nbRows; ++r) {
180 for (unsigned int c = 0; c < nbCols; ++c) {
181 char character;
182 if (vpMath::nul(I[r][c], 1e-3)) {
183 character = '0';
184 }
185 else if (I[r][c] > 0) {
186 character = '+';
187 }
188 else {
189 character = '-';
190 }
191 std::cout << character << " ";
192 }
193 std::cout << std::endl;
194 }
195 std::cout << std::endl << std::flush;
196}
197
203void print(const vpImage<unsigned char> &I, const std::string &name)
204{
205 std::cout << name << " = " << std::endl;
206 const unsigned int nbRows = I.getRows(), nbCols = I.getCols();
207 for (unsigned int r = 0; r < nbRows; ++r) {
208 for (unsigned int c = 0; c < nbCols; ++c) {
209 std::cout << std::to_string(I[r][c]) << " ";
210 }
211 std::cout << std::endl;
212 }
213 std::cout << std::endl << std::flush;
214}
215
216template <typename ImageType>
217struct vpInputImage
218{
219 std::string m_errorMsg;
220 vpImage<ImageType> m_I;
221
222 vpInputImage(const std::string &errMsg = "", const vpImage<ImageType> &I = vpImage<ImageType>())
223 : m_errorMsg(errMsg)
224 , m_I(I)
225 { }
226};
227
228typedef struct vpInputDataset
229{
230 std::vector<std::pair<std::string, vpInputImage<unsigned char>>> m_ucImages;
231 std::vector<std::pair<std::string, vpInputImage<vpHSV<unsigned char, true>>>> m_hsvUCtrue;
232 std::vector<std::pair<std::string, vpInputImage<vpHSV<unsigned char, false>>>> m_hsvUCfalse;
233 std::vector<std::pair<std::string, vpInputImage<vpHSV<double>>>> m_hsvDouble;
234 vpImage<bool> m_Imask;
235
236 vpInputDataset()
237 {
238 vpImage<vpHSV<unsigned char, true>> Ihsv_uc_true_square(11, 11, vpHSV<unsigned char, true>(0U, 0U, 0U));
239 vpImage<vpHSV<unsigned char, true>> Ihsv_uc_true_inversed = Ihsv_uc_true_square;
240 vpImage<vpHSV<unsigned char, true>> Ihsv_uc_true_horizontal = Ihsv_uc_true_square;
241 vpImage<vpHSV<unsigned char, true>> Ihsv_uc_true_vertical = Ihsv_uc_true_square;
242 vpImage<vpHSV<unsigned char, true>> Ihsv_uc_true_pyramid = Ihsv_uc_true_square;
243
244 vpImage<vpHSV<unsigned char, false>> Ihsv_uc_false_square(11, 11, vpHSV<unsigned char, false>(0U, 0U, 0U));
245 vpImage<vpHSV<unsigned char, false>> Ihsv_uc_false_inversed = Ihsv_uc_false_square;
246 vpImage<vpHSV<unsigned char, false>> Ihsv_uc_false_horizontal = Ihsv_uc_false_square;
247 vpImage<vpHSV<unsigned char, false>> Ihsv_uc_false_vertical = Ihsv_uc_false_square;
248 vpImage<vpHSV<unsigned char, false>> Ihsv_uc_false_pyramid = Ihsv_uc_false_square;
249
250 vpImage<vpHSV<double>> Ihsv_square(11, 11, vpHSV<double>(0., 0., 0.));
251 vpImage<vpHSV<double>> Ihsv_square_inversed = Ihsv_square;
252 vpImage<vpHSV<double>> Ihsv_square_horizontal = Ihsv_square;
253 vpImage<vpHSV<double>> Ihsv_square_vertical = Ihsv_square;
254 vpImage<vpHSV<double>> Ihsv_pyramid = Ihsv_square;
255
256 vpImage<unsigned char> Iuc_square(11, 11, 0);
257 vpImage<unsigned char> Iuc_square_inversed = Iuc_square;
258 vpImage<unsigned char> Iuc_square_horizontal = Iuc_square;
259 vpImage<unsigned char> Iuc_square_vertical = Iuc_square;
260 vpImage<unsigned char> Iuc_pyramid = Iuc_square;
261
262 m_Imask.resize(11, 11, false);
263
264 for (unsigned int r = 2; r <=8; ++r) {
265 for (unsigned int c = 2; c <= 8; ++c) {
266 if ((r == 2) || (r == 3) || (r==7) || (r == 8)) {
267 m_Imask[r][c] = true;
268 }
269 if ((c == 2) || (c == 3) || (c==7) || (c == 8)) {
270 m_Imask[r][c] = true;
271 }
272 double val = 0., val_inversed = 0., val_pyramid = 0.;
273 unsigned char val_c = 0, val_c_inversed = 0, val_c_pyramid = 0;
274 if (c <= 5) {
275 val = 0.1 * static_cast<double>(c - 1);
276 val_inversed = 0.1 * static_cast<double>(6 - c);
277 val_c = c - 1;
278 val_c_inversed = 6 - c;
279 }
280 else {
281 val = 0.1 * static_cast<double>(9 - c);
282 val_inversed = 0.1 * static_cast<double>(c - 4);
283 val_c = 9 - c;
284 val_c_inversed = c - 4;
285 }
286 if (r <= 5) {
287 val_pyramid = val + 0.1 * (r - 2);
288 val_c_pyramid = val_c + r - 2;
289 }
290 else {
291 val_pyramid = val + 0.1 * (8 - r);
292 val_c_pyramid = val_c + 8 - r;
293 }
294 if ((r == 2) || (r == 8) /* || (((r == 4) || (r == 6)) && ((c >=4) && (c <= 6))) */) {
295 // Horizontal lines of the square
296 Ihsv_square[r][c] = vpHSV<double>(val, val, val);
297 Ihsv_square_inversed[r][c] = vpHSV<double>(val_inversed, val_inversed, val_inversed);
298 Ihsv_square[c][r] = vpHSV<double>(val, val, val);
299 Ihsv_square_inversed[c][r] = vpHSV<double>(val_inversed, val_inversed, val_inversed);
300
301 Ihsv_uc_false_square[r][c] = vpHSV<unsigned char, false>(val_c, val_c, val_c);
302 Ihsv_uc_false_inversed[r][c] = vpHSV<unsigned char, false>(val_c_inversed, val_c_inversed, val_c_inversed);
303 Ihsv_uc_false_square[c][r] = vpHSV<unsigned char, false>(val_c, val_c, val_c);
304 Ihsv_uc_false_inversed[c][r] = vpHSV<unsigned char, false>(val_c_inversed, val_c_inversed, val_c_inversed);
305
306 Ihsv_uc_true_square[r][c] = vpHSV<unsigned char, true>(val_c, val_c, val_c);
307 Ihsv_uc_true_inversed[r][c] = vpHSV<unsigned char, true>(val_c_inversed, val_c_inversed, val_c_inversed);
308 Ihsv_uc_true_square[c][r] = vpHSV<unsigned char, true>(val_c, val_c, val_c);
309 Ihsv_uc_true_inversed[c][r] = vpHSV<unsigned char, true>(val_c_inversed, val_c_inversed, val_c_inversed);
310
311 Iuc_square[r][c] = val_c;
312 Iuc_square_inversed[r][c] = val_c_inversed;
313 Iuc_square[c][r] = val_c;
314 Iuc_square_inversed[c][r] = val_c_inversed;
315 }
316 Ihsv_square_horizontal[r][c] = vpHSV<double>(val, val, val);
317 Ihsv_uc_true_horizontal[r][c] = vpHSV<unsigned char, true>(val_c, val_c, val_c);
318 Ihsv_uc_false_horizontal[r][c] = vpHSV<unsigned char, false>(val_c, val_c, val_c);
319 Iuc_square_horizontal[r][c] = val_c;
320
321 Ihsv_square_vertical[c][r] = vpHSV<double>(val, val, val);
322 Ihsv_uc_true_vertical[c][r] = vpHSV<unsigned char, true>(val_c, val_c, val_c);
323 Ihsv_uc_false_vertical[c][r] = vpHSV<unsigned char, false>(val_c, val_c, val_c);
324 Iuc_square_vertical[c][r] = val_c;
325
326 Ihsv_pyramid[r][c] = vpHSV<double>(val_pyramid, val_pyramid, val_pyramid);
327 Ihsv_uc_true_pyramid[r][c] = vpHSV<unsigned char, true>(val_c_pyramid, val_c_pyramid, val_c_pyramid);
328 Ihsv_uc_false_pyramid[r][c] = vpHSV<unsigned char, false>(val_c_pyramid, val_c_pyramid, val_c_pyramid);
329 Iuc_pyramid[r][c] = val_c_pyramid;
330 }
331 }
332 m_ucImages.emplace_back("Iuc_square", vpInputImage<unsigned char>("", Iuc_square));
333 m_ucImages.emplace_back("Iuc_square_inversed", vpInputImage<unsigned char>("", Iuc_square_inversed));
334 m_ucImages.emplace_back("Iuc_square_horizontal", vpInputImage<unsigned char>("GX is expected to have values on the whole surface of the square, GY only on the borders", Iuc_square_horizontal));
335 m_ucImages.emplace_back("Iuc_square_vertical", vpInputImage<unsigned char>("GY is expected to have values on the whole surface of the square, GX only on the borders", Iuc_square_vertical));
336 m_ucImages.emplace_back("Iuc_pyramid", vpInputImage<unsigned char>("GX and GY are expected to have values on the whole square", Iuc_pyramid));
337
338 m_hsvUCtrue.emplace_back("Ihsv_uc_true_square", vpInputImage<vpHSV<unsigned char, true>>("", Ihsv_uc_true_square));
339 m_hsvUCtrue.emplace_back("Ihsv_uc_true_inversed", vpInputImage<vpHSV<unsigned char, true>>("", Ihsv_uc_true_inversed));
340 m_hsvUCtrue.emplace_back("Ihsv_uc_true_horizontal", vpInputImage<vpHSV<unsigned char, true>>("GX is expected to have values on the whole surface of the square, GY only on the borders", Ihsv_uc_true_horizontal));
341 m_hsvUCtrue.emplace_back("Ihsv_uc_true_vertical", vpInputImage<vpHSV<unsigned char, true>>("GY is expected to have values on the whole surface of the square, GX only on the borders", Ihsv_uc_true_vertical));
342 m_hsvUCtrue.emplace_back("Ihsv_uc_true_pyramid", vpInputImage<vpHSV<unsigned char, true>>("GX and GY are expected to have values on the whole square", Ihsv_uc_true_pyramid));
343
344 m_hsvUCfalse.emplace_back("Ihsv_uc_false_square", vpInputImage<vpHSV<unsigned char, false>>("", Ihsv_uc_false_square));
345 m_hsvUCfalse.emplace_back("Ihsv_uc_false_inversed", vpInputImage<vpHSV<unsigned char, false>>("", Ihsv_uc_false_inversed));
346 m_hsvUCfalse.emplace_back("Ihsv_uc_false_horizontal", vpInputImage<vpHSV<unsigned char, false>>("GX is expected to have values on the whole surface of the square, GY only on the borders", Ihsv_uc_false_horizontal));
347 m_hsvUCfalse.emplace_back("Ihsv_uc_false_vertical", vpInputImage<vpHSV<unsigned char, false>>("GY is expected to have values on the whole surface of the square, GX only on the borders", Ihsv_uc_false_vertical));
348 m_hsvUCfalse.emplace_back("Ihsv_uc_false_pyramid", vpInputImage<vpHSV<unsigned char, false>>("GX and GY are expected to have values on the whole square", Ihsv_uc_false_pyramid));
349
350 m_hsvDouble.emplace_back("I_hsv_double_square", vpInputImage<vpHSV<double>>("", Ihsv_square));
351 m_hsvDouble.emplace_back("Ihsv_double_square_inversed", vpInputImage<vpHSV<double>>("", Ihsv_square_inversed));
352 m_hsvDouble.emplace_back("Ihsv_double_horizontal", vpInputImage<vpHSV<double>>("GX is expected to have values on the whole surface of the square, GY only on the borders", Ihsv_square_horizontal));
353 m_hsvDouble.emplace_back("Ihsv_double_vertical", vpInputImage<vpHSV<double>>("GY is expected to have values on the whole surface of the square, GX only on the borders", Ihsv_square_vertical));
354 m_hsvDouble.emplace_back("Ihsv_double_pyramid", vpInputImage<vpHSV<double>>("GX and GY are expected to have values on the whole square", Ihsv_pyramid));
355 }
356}vpInputDataset;
357}
358#endif
359END_VISP_NAMESPACE
360#endif
361#endif
static ArithmeticType & get(vpHSV< ArithmeticType, useFullScale > &col)
Setter for a channel of a HSV pixel.
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 getCols() const
Definition vpImage.h:171
unsigned int getHeight() const
Definition vpImage.h:181
unsigned int getRows() const
Definition vpImage.h:212
static bool nul(double x, double threshold=0.001)
Definition vpMath.h:453