Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testRGBaToHSV.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 * Description:
31 * Test vpImageConvert::convert() function for RGBa to HSV.
32 */
38
39#include <iostream>
40#include <limits>
41
42#include <visp3/core/vpImage.h>
43#include <visp3/core/vpImageConvert.h>
44#include <visp3/core/vpRGBa.h>
45#include <visp3/core/vpHSV.h>
46
47#include "hsvUtils.h"
48
49#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
50
51#ifdef ENABLE_VISP_NAMESPACE
52using namespace VISP_NAMESPACE_NAME;
53#endif
54
55#ifndef DOXYGEN_SHOULD_SKIP_THIS
68template<typename Type, bool useFullScale >
69bool test_hsv(const vpHSV<Type, useFullScale> &hsv_computed, const vpRGBa &rgb_truth,
70 const vpHSV<Type, useFullScale> &hsv_truth, const double &thresh = 0.001)
71{
72 // Compare HSV values
73 if ((!vpMath::equal(hsv_computed.H, hsv_truth.H, thresh)) ||
74 (!vpMath::equal(hsv_computed.S, hsv_truth.S, thresh)) ||
75 (!vpMath::equal(hsv_computed.V, hsv_truth.V, thresh))) {
76
77 std::cout << static_cast<int>(rgb_truth.R) << ","
78 << static_cast<int>(rgb_truth.G) << ","
79 << static_cast<int>(rgb_truth.B) << "): Expected hsv value: ("
80 << static_cast<int>(hsv_truth.H) << ","
81 << static_cast<int>(hsv_truth.S) << ","
82 << static_cast<int>(hsv_truth.V) << ") converted value: ("
83 << static_cast<int>(hsv_computed.H) << ","
84 << static_cast<int>(hsv_computed.S) << ","
85 << static_cast<int>(hsv_computed.V) << ")" << std::endl;
86 return false;
87 }
88
89 return true;
90}
91#endif
92
93int main()
94{
95 bool isSuccess = true;
96
97 std::vector< vpColVector > rgb_truth;
98 rgb_truth.emplace_back(std::vector<double>({ 0, 0, 0, vpRGBa::alpha_default }));
99 rgb_truth.emplace_back(std::vector<double>({ 255, 255, 255, vpRGBa::alpha_default }));
100 rgb_truth.emplace_back(std::vector<double>({ 255, 0, 0, vpRGBa::alpha_default }));
101 rgb_truth.emplace_back(std::vector<double>({ 0, 255, 0, vpRGBa::alpha_default }));
102 rgb_truth.emplace_back(std::vector<double>({ 0, 0, 255, vpRGBa::alpha_default }));
103 rgb_truth.emplace_back(std::vector<double>({ 255, 255, 0, vpRGBa::alpha_default }));
104 rgb_truth.emplace_back(std::vector<double>({ 0, 255, 255, vpRGBa::alpha_default }));
105 rgb_truth.emplace_back(std::vector<double>({ 255, 0, 255, vpRGBa::alpha_default }));
106 rgb_truth.emplace_back(std::vector<double>({ 128, 128, 128, vpRGBa::alpha_default }));
107 rgb_truth.emplace_back(std::vector<double>({ 128, 128, 0, vpRGBa::alpha_default }));
108 rgb_truth.emplace_back(std::vector<double>({ 128, 0, 0, vpRGBa::alpha_default }));
109 rgb_truth.emplace_back(std::vector<double>({ 0, 128, 0, vpRGBa::alpha_default }));
110 rgb_truth.emplace_back(std::vector<double>({ 0, 128, 128, vpRGBa::alpha_default }));
111 rgb_truth.emplace_back(std::vector<double>({ 0, 0, 128, vpRGBa::alpha_default }));
112 rgb_truth.emplace_back(std::vector<double>({ 128, 0, 128, vpRGBa::alpha_default }));
113
114 double h_max;
115 bool h_full;
116 size_t size = rgb_truth.size();
117
118 for (size_t test = 0; test < 2; ++test) {
119 if (test == 0) {
120 h_max = 255;
121 h_full = true;
122 }
123 else {
125 h_full = false;
126 }
127
128 // See https://www.rapidtables.com/convert/color/hsv-to-rgb.html
129 std::vector< vpColVector > hsv_truth;
130 hsv_truth.emplace_back(std::vector<double>({ 0., 0., 0. }));
131 hsv_truth.emplace_back(std::vector<double>({ 0., 0., 255. }));
132 hsv_truth.emplace_back(std::vector<double>({ 0., 255., 255. }));
133 hsv_truth.emplace_back(std::vector<double>({ h_max * 120. / 360., 255., 255. }));
134 hsv_truth.emplace_back(std::vector<double>({ h_max * 240. / 360., 255., 255. }));
135 hsv_truth.emplace_back(std::vector<double>({ h_max * 60. / 360., 255., 255. }));
136 hsv_truth.emplace_back(std::vector<double>({ h_max * 180. / 360., 255., 255. }));
137 hsv_truth.emplace_back(std::vector<double>({ h_max * 300. / 360., 255., 255. }));
138 hsv_truth.emplace_back(std::vector<double>({ 0., 0., 128. }));
139 hsv_truth.emplace_back(std::vector<double>({ h_max * 60. / 360., 255., 128. }));
140 hsv_truth.emplace_back(std::vector<double>({ 0., 255., 128. }));
141 hsv_truth.emplace_back(std::vector<double>({ h_max * 120. / 360., 255., 128. }));
142 hsv_truth.emplace_back(std::vector<double>({ h_max * 180. / 360., 255., 128. }));
143 hsv_truth.emplace_back(std::vector<double>({ h_max * 240. / 360., 255., 128. }));
144 hsv_truth.emplace_back(std::vector<double>({ h_max * 300. / 360., 255., 128. }));
145
146 // SECTION("RGB -> HSV (unsigned char) -> RGB")
147 std::cout << std::endl << "----- Test rgba -> hsv (unsigned char) conversion with h full scale: " << (h_full ? "yes" : "no") << " -----" << std::endl;
148 for (unsigned int id = 0; id < size; ++id) {
149 vpRGBa rgba(rgb_truth[id]);
150 if (h_full) {
151 vpHSV<unsigned char, true> hsv(static_cast<unsigned char>(0), static_cast<unsigned char>(0), static_cast<unsigned char>(0));
152 hsv.buildFrom(rgba);
153 isSuccess = isSuccess && test_hsv(hsv, rgba, vpHSV<unsigned char, true>(hsv_truth[id]), 1.5); // 1.5 due to rounding errors on Fedora
154 }
155 else {
156 vpHSV<unsigned char, false> hsv(static_cast<unsigned char>(0), static_cast<unsigned char>(0), static_cast<unsigned char>(0));
157 hsv.buildFrom(rgba);
158 isSuccess = isSuccess && test_hsv(hsv, rgba, vpHSV<unsigned char, false>(hsv_truth[id]), 1.5); // 1.5 due to rounding errors on Fedora
159 }
160
161 }
162
163 if (h_full) {
164 // SECTION("RGB -> HSV (double) -> RGB")
165 std::cout << std::endl << "----- Test rgb -> hsv (double) conversion -----" << std::endl;
166 for (unsigned int id = 0; id < size; ++id) {
167 vpRGBa rgba(rgb_truth[id]);
168 vpHSV<double> hsv(rgba);
169 for (unsigned char c = 0; c < vpHSV<double>::nbChannels; ++c) {
170 hsv_truth[id][c] = hsv_truth[id][c] / 255.;
171 }
172 isSuccess = isSuccess && test_hsv(hsv, rgba, vpHSV<double>(hsv_truth[id]));
173 }
174 }
175 }
176
177 std::cout << std::endl << "----- Testing vpImageConvert::convert(vpImage<vpRGBa>, vpImage<vpHSV>) conversions -----" << std::endl;
178 vpImage<vpRGBa> Irgb(480, 640, vpRGBa(128, 128, 128));
179 vpImage<vpHSV<unsigned char, false>> Ihsvucf_truth(480, 640, vpHSV<unsigned char, false>(0, 0, 128)), Ihsvucf;
180 vpImage<vpHSV<unsigned char, true>> Ihsvuct_truth(480, 640, vpHSV<unsigned char, true>(0, 0, 128)), Ihsvuct;
181 vpImage<vpHSV<double>> Ihsvd_truth(480, 640, vpHSV<double>(0., 0., 0.5)), Ihsvd;
182 vpImageConvert::convert(Irgb, Ihsvucf);
183 vpImageConvert::convert(Irgb, Ihsvuct);
184 vpImageConvert::convert(Irgb, Ihsvd);
185
186 bool localSuccess = vpHSVTests::areAlmostEqual(Ihsvucf, "Ihsvucf", Ihsvucf_truth, "Ihsvucf_truth", 1.0);
187 if (!localSuccess) {
188 std::cerr << "vpImageConvert(rgba, hsv<uchar, false>) failed!" << std::endl;
189 }
190 isSuccess = isSuccess && localSuccess;
191
192 localSuccess = vpHSVTests::areAlmostEqual(Ihsvuct, "Ihsvuct", Ihsvuct_truth, "Ihsvuct_truth", 1.0);
193 if (!localSuccess) {
194 std::cerr << "vpImageConvert(rgba, hsv<uchar, true>) failed!" << std::endl;
195 }
196 isSuccess = isSuccess && localSuccess;
197
198 localSuccess = vpHSVTests::areAlmostEqual(Ihsvd, "Ihsvd", Ihsvd_truth, "Ihsvd_truth");
199 if (!localSuccess) {
200 std::cerr << "vpImageConvert(rgba, hsv<double>) failed!" << std::endl;
201 }
202 isSuccess = isSuccess && localSuccess;
203
204 if (isSuccess) {
205 std::cout << "All tests were successful !" << std::endl;
206 return EXIT_SUCCESS;
207 }
208 std::cerr << "ERROR: Something went wrong !" << std::endl;
209 return EXIT_FAILURE;
210}
211
212#else
213int main()
214{
215 std::cout << "vpHSV class is not available, please use CXX 11 standard" << std::endl;
216 return EXIT_SUCCESS;
217}
218#endif
Class implementing the HSV pixel format.
Definition vpHSV.h:135
T V
Definition vpHSV.h:539
T S
Definition vpHSV.h:538
static constexpr unsigned char maxHueUsingLimitedRange
Maximum value of the Hue channel when using unsigned char and the limited range.
Definition vpHSV.h:549
T H
Definition vpHSV.h:537
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Definition of the vpImage class member functions.
Definition vpImage.h:131
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:470
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
@ alpha_default
Definition vpRGBa.h:76