Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testHSVtoRGBa.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 HSV to RGBa.
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
67template<typename Type, bool useFullScale >
68bool test_rgb(const vpRGBa &rgb_computed, const vpRGBa &rgb_truth,
69 const vpHSV<Type, useFullScale> &hsv_truth)
70{
71 // Compare RGB values
72 if ((rgb_computed.R != rgb_truth.R) ||
73 (rgb_computed.G != rgb_truth.G) ||
74 (rgb_computed.B != rgb_truth.B)) {
75
76 std::cout << static_cast<int>(hsv_truth.H) << ","
77 << static_cast<int>(hsv_truth.S) << ","
78 << static_cast<int>(hsv_truth.V) << "): Expected RGB value: ("
79 << static_cast<int>(rgb_truth.R) << ","
80 << static_cast<int>(rgb_truth.G) << ","
81 << static_cast<int>(rgb_truth.B) << ") converted value: ("
82 << static_cast<int>(rgb_computed.R) << ","
83 << static_cast<int>(rgb_computed.G) << ","
84 << static_cast<int>(rgb_computed.B) << ")" << std::endl;
85 return false;
86 }
87
88 return true;
89}
90#endif
91
92int main()
93{
94 bool isSuccess = true;
95
96 std::vector< vpColVector> rgb_truth;
97 rgb_truth.emplace_back(std::vector<double>({ 0, 0, 0, vpRGBa::alpha_default }));
98 rgb_truth.emplace_back(std::vector<double>({ 255, 255, 255, vpRGBa::alpha_default }));
99 rgb_truth.emplace_back(std::vector<double>({ 255, 0, 0, vpRGBa::alpha_default }));
100 rgb_truth.emplace_back(std::vector<double>({ 0, 255, 0, vpRGBa::alpha_default }));
101 rgb_truth.emplace_back(std::vector<double>({ 0, 0, 255, vpRGBa::alpha_default }));
102 rgb_truth.emplace_back(std::vector<double>({ 255, 255, 0, vpRGBa::alpha_default }));
103 rgb_truth.emplace_back(std::vector<double>({ 0, 255, 255, vpRGBa::alpha_default }));
104 rgb_truth.emplace_back(std::vector<double>({ 255, 0, 255, vpRGBa::alpha_default }));
105 rgb_truth.emplace_back(std::vector<double>({ 128, 128, 128, vpRGBa::alpha_default }));
106 rgb_truth.emplace_back(std::vector<double>({ 128, 128, 0, vpRGBa::alpha_default }));
107 rgb_truth.emplace_back(std::vector<double>({ 128, 0, 0, vpRGBa::alpha_default }));
108 rgb_truth.emplace_back(std::vector<double>({ 0, 128, 0, vpRGBa::alpha_default }));
109 rgb_truth.emplace_back(std::vector<double>({ 0, 128, 128, vpRGBa::alpha_default }));
110 rgb_truth.emplace_back(std::vector<double>({ 0, 0, 128, vpRGBa::alpha_default }));
111 rgb_truth.emplace_back(std::vector<double>({ 128, 0, 128, vpRGBa::alpha_default }));
112
113 double h_max;
114 bool h_full;
115 size_t size = rgb_truth.size();
116
117 for (size_t test = 0; test < 2; ++test) {
118 if (test == 0) {
119 h_max = 255;
120 h_full = true;
121 }
122 else {
124 h_full = false;
125 }
126
127 // See https://www.rapidtables.com/convert/color/hsv-to-rgb.html
128 std::vector< vpColVector > hsv_truth;
129 hsv_truth.emplace_back(std::vector<double>({ 0., 0., 0. }));
130 hsv_truth.emplace_back(std::vector<double>({ 0., 0., 255. }));
131 hsv_truth.emplace_back(std::vector<double>({ 0., 255., 255. }));
132 hsv_truth.emplace_back(std::vector<double>({ h_max * 120. / 360., 255., 255. }));
133 hsv_truth.emplace_back(std::vector<double>({ h_max * 240. / 360., 255., 255. }));
134 hsv_truth.emplace_back(std::vector<double>({ h_max * 60. / 360., 255., 255. }));
135 hsv_truth.emplace_back(std::vector<double>({ h_max * 180. / 360., 255., 255. }));
136 hsv_truth.emplace_back(std::vector<double>({ h_max * 300. / 360., 255., 255. }));
137 hsv_truth.emplace_back(std::vector<double>({ 0., 0., 128. }));
138 hsv_truth.emplace_back(std::vector<double>({ h_max * 60. / 360., 255., 128. }));
139 hsv_truth.emplace_back(std::vector<double>({ 0., 255., 128. }));
140 hsv_truth.emplace_back(std::vector<double>({ h_max * 120. / 360., 255., 128. }));
141 hsv_truth.emplace_back(std::vector<double>({ h_max * 180. / 360., 255., 128. }));
142 hsv_truth.emplace_back(std::vector<double>({ h_max * 240. / 360., 255., 128. }));
143 hsv_truth.emplace_back(std::vector<double>({ h_max * 300. / 360., 255., 128. }));
144
145 // SECTION("HSV (unsigned char) -> RGB")
146 std::cout << std::endl << "----- Test hsv (unsigned char) -> rgba conversion with h full scale: " << (h_full ? "yes" : "no") << " -----" << std::endl;
147 for (unsigned int id = 0; id < size; ++id) {
148 vpRGBa rgba_truth(rgb_truth[id]);
149 if (h_full) {
150 if (vpMath::round(hsv_truth[id][0] * 10.) % 10 == 0) { // To avoid the problem that 360 / 255 is not an integer
151 std::cout << "Running the test for H = " << hsv_truth[id][0] << " ..." << std::endl;
152 vpHSV<unsigned char, true> hsv(static_cast<unsigned char>(hsv_truth[id][0]), static_cast<unsigned char>(hsv_truth[id][1]), static_cast<unsigned char>(hsv_truth[id][2]));
153 vpRGBa rgba(hsv);
154 isSuccess = isSuccess && test_rgb(rgba, rgba_truth, hsv);
155 }
156 }
157 else {
158 if (vpMath::round(hsv_truth[id][0] * 10.) % 10 == 0) { // To avoid the problem that 360 / 255 is not an integer
159 std::cout << "Running the test for H = " << hsv_truth[id][0] << " ..." << std::endl;
160 vpHSV<unsigned char, false> hsv(static_cast<unsigned char>(hsv_truth[id][0]), static_cast<unsigned char>(hsv_truth[id][1]), static_cast<unsigned char>(hsv_truth[id][2]));
161 vpRGBa rgba(hsv);
162 isSuccess = isSuccess && test_rgb(rgba, rgba_truth, hsv);
163 }
164 }
165
166 }
167
168 if (h_full) {
169 // SECTION("HSV (double) -> RGB")
170 std::cout << std::endl << "----- Test hsv (double) -> rgba conversion -----" << std::endl;
171 for (unsigned int id = 0; id < size; ++id) {
172 vpRGBa rgba_truth(rgb_truth[id]);
173 vpColVector hsv_vec = hsv_truth[id];
174 std::cout << "Running the test for HSV = " << hsv_truth[id][0] << " ; " << hsv_truth[id][1] << "; " << hsv_truth[id][2] << " ..." << std::endl;
175 for (unsigned char c = 0; c < vpHSV<double>::nbChannels; ++c) {
176 hsv_vec[c] = hsv_vec[c] / 255.;
177 }
178 vpHSV<double> hsv(hsv_vec);
179 vpRGBa rgba(hsv);
180 isSuccess = isSuccess && test_rgb(rgba, rgba_truth, hsv);
181 }
182 }
183 }
184
185 std::cout << std::endl << "----- Testing vpImageConvert::convert(vpImage<vpHSV>, vpImage<vpRGBa>) conversions -----" << std::endl;
186 vpImage<vpRGBa> Irgb_truth(480, 640, vpRGBa(128, 128, 128)), Irgb;
187 vpImage<vpHSV<unsigned char, false>> Ihsvucf_truth(480, 640, vpHSV<unsigned char, false>(0, 0, 128));
188 vpImage<vpHSV<unsigned char, true>> Ihsvuct_truth(480, 640, vpHSV<unsigned char, true>(0, 0, 128));
189 vpImage<vpHSV<double>> Ihsvd_truth(480, 640, vpHSV<double>(0., 0., 0.5));
190
191 vpImageConvert::convert(Ihsvucf_truth, Irgb);
192 bool localSuccess = vpHSVTests::areAlmostEqual(Irgb, "Irgb", Irgb_truth, "Irgb_truth");
193 if (!localSuccess) {
194 std::cerr << "vpImageConvert(hsv<uchar, false>, rgba) failed!" << std::endl;
195 }
196 isSuccess = isSuccess && localSuccess;
197
198 vpImageConvert::convert(Ihsvuct_truth, Irgb);
199 localSuccess = vpHSVTests::areAlmostEqual(Irgb, "Irgb", Irgb_truth, "Irgb_truth");
200 if (!localSuccess) {
201 std::cerr << "vpImageConvert(hsv<uchar, true>, rgba) failed!" << std::endl;
202 }
203 isSuccess = isSuccess && localSuccess;
204
205 vpImageConvert::convert(Ihsvd_truth, Irgb);
206 localSuccess = vpHSVTests::areAlmostEqual(Irgb, "Irgb", Irgb_truth, "Irgb_truth");
207 if (!localSuccess) {
208 std::cerr << "vpImageConvert(hsv<double>, rgba) failed!" << std::endl;
209 }
210 isSuccess = isSuccess && localSuccess;
211
212 if (isSuccess) {
213 std::cout << "All tests were successful !" << std::endl;
214 return EXIT_SUCCESS;
215 }
216 std::cerr << "ERROR: Something went wrong !" << std::endl;
217 return EXIT_FAILURE;
218}
219
220#else
221int main()
222{
223 std::cout << "vpHSV class is not available, please use CXX 11 standard" << std::endl;
224 return EXIT_SUCCESS;
225}
226#endif
Implementation of column vector and the associated operations.
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 int round(double x)
Definition vpMath.h:413
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