Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpImageConvert_hsv.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 * Convert image types.
32 */
33
38
39#if defined(_OPENMP)
40#include <omp.h>
41#endif
42
43#include <visp3/core/vpConfig.h>
44#include <visp3/core/vpImageConvert.h>
45
58 void vpImageConvert::HSV2RGB(const double *hue_, const double *saturation_, const double *value_, unsigned char *rgb,
59 unsigned int size, unsigned int step)
60{
61 int size_ = static_cast<int>(size);
62#if defined(_OPENMP)
63#pragma omp parallel for
64#endif
65 for (int i = 0; i < size_; ++i) {
66 double hue = hue_[i], saturation = saturation_[i], value = value_[i];
67
68 if (vpMath::equal(saturation, 0.0, std::numeric_limits<double>::epsilon())) {
69 hue = value;
70 saturation = value;
71 }
72 else {
73 double h = hue * 6.0;
74 double s = saturation;
75 double v = value;
76
77 if (vpMath::equal(h, 6.0, std::numeric_limits<double>::epsilon())) {
78 h = 0.0;
79 }
80
81 double f = h - static_cast<int>(h);
82 double p = v * (1.0 - s);
83 double q = v * (1.0 - (s * f));
84 double t = v * (1.0 - (s * (1.0 - f)));
85
86 const int val_2 = 2;
87 const int val_3 = 3;
88 const int val_4 = 4;
89 switch (static_cast<int>(h)) {
90 case 0:
91 hue = v;
92 saturation = t;
93 value = p;
94 break;
95
96 case 1:
97 hue = q;
98 saturation = v;
99 value = p;
100 break;
101
102 case val_2:
103 hue = p;
104 saturation = v;
105 value = t;
106 break;
107
108 case val_3:
109 hue = p;
110 saturation = q;
111 value = v;
112 break;
113
114 case val_4:
115 hue = t;
116 saturation = p;
117 value = v;
118 break;
119
120 default: // case 5:
121 hue = v;
122 saturation = p;
123 value = q;
124 break;
125 }
126 }
127
128 unsigned int i_step = static_cast<unsigned int>(i) * step;
129 rgb[i_step] = static_cast<unsigned char>(vpMath::round(hue * 255.0));
130 rgb[++i_step] = static_cast<unsigned char>(vpMath::round(saturation * 255.0));
131 rgb[++i_step] = static_cast<unsigned char>(vpMath::round(value * 255.0));
132 const int val_3 = 3;
133 if (i_step == val_3) { // alpha
134 ++i_step;
135 rgb[i_step] = vpRGBa::alpha_default;
136 }
137 }
138}
139
152void vpImageConvert::HSV2RGB(const unsigned char *hue_, const unsigned char *saturation_, const unsigned char *value_,
153 unsigned char *rgb, unsigned int size, unsigned int step, bool h_full)
154{
155 const int val_2 = 2;
156 const int val_3 = 3;
157 const int val_4 = 4;
158 float h_max;
159 if (h_full) {
160 h_max = 255.f;
161 }
162 else {
163 h_max = 180.f;
164 }
165 int size_ = static_cast<int>(size);
166#if defined(_OPENMP)
167#pragma omp parallel for
168#endif
169 for (int i = 0; i < size_; ++i) {
170 float hue = hue_[i] / h_max;
171 float saturation = saturation_[i] / 255.f;
172 float value = value_[i] / 255.f;
173
174 if (vpMath::equal(saturation, 0.f, std::numeric_limits<float>::epsilon())) {
175 hue = value;
176 saturation = value;
177 }
178 else {
179 float h = hue * 6.f;
180 float s = saturation;
181 float v = value;
182
183 if (vpMath::equal(h, 6.f, std::numeric_limits<float>::epsilon())) {
184 h = 0.0f;
185 }
186 float f = h - static_cast<float>(static_cast<int>(h));
187 float p = v * (1.0f - s);
188 float q = v * (1.0f - (s * f));
189 float t = v * (1.0f - (s * (1.0f - f)));
190
191 switch (static_cast<int>(h)) {
192 case 0:
193 hue = v;
194 saturation = t;
195 value = p;
196 break;
197
198 case 1:
199 hue = q;
200 saturation = v;
201 value = p;
202 break;
203
204 case val_2:
205 hue = p;
206 saturation = v;
207 value = t;
208 break;
209
210 case val_3:
211 hue = p;
212 saturation = q;
213 value = v;
214 break;
215
216 case val_4:
217 hue = t;
218 saturation = p;
219 value = v;
220 break;
221
222 default: // case 5:
223 hue = v;
224 saturation = p;
225 value = q;
226 break;
227 }
228 }
229
230 unsigned int i_step = static_cast<unsigned int>(i) * step;
231 rgb[i_step] = static_cast<unsigned char>(hue * 255.f);
232 rgb[++i_step] = static_cast<unsigned char>(saturation * 255.0f);
233 rgb[++i_step] = static_cast<unsigned char>(value * 255.0f);
234 if (i_step == val_3) { // alpha
235 ++i_step;
236 rgb[i_step] = vpRGBa::alpha_default;
237 }
238 }
239}
240
254void vpImageConvert::RGB2HSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
255 unsigned int size, unsigned int step)
256{
257 int size_ = static_cast<int>(size);
258 int step_ = static_cast<int>(step);
259#if defined(_OPENMP)
260#pragma omp parallel for
261#endif
262 for (int i = 0; i < size_; ++i) {
263 double red, green, blue;
264 double h, s, v;
265 double min, max;
266 int i_ = i * step_;
267
268 red = rgb[i_] / 255.0;
269 ++i_;
270 green = rgb[i_] / 255.0;
271 ++i_;
272 blue = rgb[i_] / 255.0;
273
274 if (red > green) {
275 max = std::max<double>(red, blue);
276 min = std::min<double>(green, blue);
277 }
278 else {
279 max = std::max<double>(green, blue);
280 min = std::min<double>(red, blue);
281 }
282
283 v = max;
284
285 if (!vpMath::equal(max, 0.0, std::numeric_limits<double>::epsilon())) {
286 s = (max - min) / max;
287 }
288 else {
289 s = 0.0;
290 }
291
292 if (vpMath::equal(s, 0.0, std::numeric_limits<double>::epsilon())) {
293 h = 0.0;
294 }
295 else {
296 double delta = max - min;
297
298 if (vpMath::equal(red, max, std::numeric_limits<double>::epsilon())) {
299 h = (green - blue) / delta;
300 }
301 else if (vpMath::equal(green, max, std::numeric_limits<double>::epsilon())) {
302 h = 2.0 + ((blue - red) / delta);
303 }
304 else {
305 h = 4.0 + ((red - green) / delta);
306 }
307
308 h /= 6.0;
309 if (h < 0.0) {
310 h += 1.0;
311 }
312 else if (h > 1.0) {
313 h -= 1.0;
314 }
315 }
316
317 hue[i] = h;
318 saturation[i] = s;
319 value[i] = v;
320 }
321}
322
337void vpImageConvert::RGB2HSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation, unsigned char *value,
338 unsigned int size, unsigned int step, bool h_full)
339{
340 int size_ = static_cast<int>(size);
341 std::vector<float> h_scale(4);
342 const unsigned int index_0 = 0;
343 const unsigned int index_1 = 1;
344 const unsigned int index_2 = 2;
345 const unsigned int index_3 = 3;
346 if (h_full) {
347 h_scale[index_0] = 42.5f;
348 h_scale[index_1] = 85.f;
349 h_scale[index_2] = 170.f;
350 h_scale[index_3] = 255.f;
351 }
352 else {
353 h_scale[index_0] = 30.f;
354 h_scale[index_1] = 60.f;
355 h_scale[index_2] = 120.f;
356 h_scale[index_3] = 180.f;
357 }
358#if defined(_OPENMP)
359#pragma omp parallel for
360#endif
361 for (int i = 0; i < size_; ++i) {
362 float red, green, blue;
363 float h, s, v;
364 float min, max;
365 unsigned int i_ = static_cast<unsigned int>(i) * step;
366
367 red = rgb[i_];
368 green = rgb[++i_];
369 blue = rgb[++i_];
370
371 if (red > green) {
372 max = std::max<float>(red, blue);
373 min = std::min<float>(green, blue);
374 }
375 else {
376 max = std::max<float>(green, blue);
377 min = std::min<float>(red, blue);
378 }
379
380 v = max;
381
382 if (!vpMath::equal(max, 0.f, std::numeric_limits<float>::epsilon())) {
383 s = (255.f * (max - min)) / max;
384 }
385 else {
386 s = 0.f;
387 }
388
389 if (vpMath::equal(s, 0.f, std::numeric_limits<float>::epsilon())) {
390 h = 0.f;
391 }
392 else {
393 float delta = max - min;
394
395 if (vpMath::equal(red, max, std::numeric_limits<float>::epsilon())) {
396 h = (h_scale[index_0] * (green - blue)) / delta;
397 }
398 else if (vpMath::equal(green, max, std::numeric_limits<float>::epsilon())) {
399 h = h_scale[index_1] + ((h_scale[index_0] * (blue - red)) / delta);
400 }
401 else {
402 h = h_scale[index_2] + ((h_scale[index_0] * (red - green)) / delta);
403 }
404
405 if (h < 0.f) {
406 h += h_scale[index_3];
407 }
408 }
409
410 hue[i] = static_cast<unsigned char>(h);
411 saturation[i] = static_cast<unsigned char>(s);
412 value[i] = static_cast<unsigned char>(v);
413 }
414}
415
429void vpImageConvert::HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba,
430 unsigned int size)
431{
432 const unsigned int val_4 = 4;
433 vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, val_4);
434}
435
450void vpImageConvert::HSVToRGBa(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
451 unsigned char *rgba, unsigned int size, bool h_full)
452{
453 const unsigned int val_4 = 4;
454 vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, val_4, h_full);
455}
456
472void vpImageConvert::RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value,
473 unsigned int size)
474{
475 const unsigned int val_4 = 4;
476 vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, val_4);
477}
478
496void vpImageConvert::RGBaToHSV(const unsigned char *rgba, unsigned char *hue, unsigned char *saturation,
497 unsigned char *value, unsigned int size, bool h_full)
498{
499 const unsigned int val_4 = 4;
500 vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, val_4, h_full);
501}
502
516void vpImageConvert::HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb,
517 unsigned int size)
518{
519 const unsigned int val_3 = 3;
520 vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, val_3);
521}
522
537void vpImageConvert::HSVToRGB(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
538 unsigned char *rgb, unsigned int size, bool h_full)
539{
540 const unsigned int val_3 = 3;
541 vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, val_3, h_full);
542}
543
556void vpImageConvert::RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
557 unsigned int size)
558{
559 const unsigned int val_3 = 3;
560 vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, val_3);
561}
562
578void vpImageConvert::RGBToHSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation,
579 unsigned char *value, unsigned int size, bool h_full)
580{
581 const unsigned int val_3 = 3;
582 vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, val_3, h_full);
583}
584END_VISP_NAMESPACE
static void HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba, unsigned int size)
static void RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value, unsigned int size)
static void RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value, unsigned int size)
static void HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb, unsigned int size)
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:470
static int round(double x)
Definition vpMath.h:413
@ alpha_default
Definition vpRGBa.h:76