Visual Servoing Platform  version 3.6.1 under development (2024-04-29)
vpImageConvert_hsv.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Convert image types.
33  *
34 *****************************************************************************/
35 
41 #if defined(_OPENMP)
42 #include <omp.h>
43 #endif
44 
45 #include <visp3/core/vpConfig.h>
46 #include <visp3/core/vpImageConvert.h>
47 
59 void vpImageConvert::HSV2RGB(const double *hue_, const double *saturation_, const double *value_, unsigned char *rgb,
60  unsigned int size, unsigned int step)
61 {
62  int size_ = static_cast<int>(size);
63 #if defined(_OPENMP)
64 #pragma omp parallel for
65 #endif
66  for (int i = 0; i < size_; ++i) {
67  double hue = hue_[i], saturation = saturation_[i], value = value_[i];
68 
69  if (vpMath::equal(saturation, 0.0, std::numeric_limits<double>::epsilon())) {
70  hue = value;
71  saturation = value;
72  }
73  else {
74  double h = hue * 6.0;
75  double s = saturation;
76  double v = value;
77 
78  if (vpMath::equal(h, 6.0, std::numeric_limits<double>::epsilon())) {
79  h = 0.0;
80  }
81 
82  double f = h - static_cast<int>(h);
83  double p = v * (1.0 - s);
84  double q = v * (1.0 - (s * f));
85  double t = v * (1.0 - (s * (1.0 - f)));
86 
87  switch (static_cast<int>(h)) {
88  case 0:
89  hue = v;
90  saturation = t;
91  value = p;
92  break;
93 
94  case 1:
95  hue = q;
96  saturation = v;
97  value = p;
98  break;
99 
100  case 2:
101  hue = p;
102  saturation = v;
103  value = t;
104  break;
105 
106  case 3:
107  hue = p;
108  saturation = q;
109  value = v;
110  break;
111 
112  case 4:
113  hue = t;
114  saturation = p;
115  value = v;
116  break;
117 
118  default: // case 5:
119  hue = v;
120  saturation = p;
121  value = q;
122  break;
123  }
124  }
125 
126  int i_step = i * step;
127  rgb[i_step] = static_cast<unsigned char>(vpMath::round(hue * 255.0));
128  rgb[++i_step] = static_cast<unsigned char>(vpMath::round(saturation * 255.0));
129  rgb[++i_step] = static_cast<unsigned char>(vpMath::round(value * 255.0));
130  if ((++i_step) == 3) { // alpha
131  rgb[i_step] = vpRGBa::alpha_default;
132  }
133  }
134 }
135 
148 void vpImageConvert::HSV2RGB(const unsigned char *hue_, const unsigned char *saturation_, const unsigned char *value_,
149  unsigned char *rgb, unsigned int size, unsigned int step, bool h_full)
150 {
151  float h_max;
152  if (h_full) {
153  h_max = 255.f;
154  }
155  else {
156  h_max = 180.f;
157  }
158  int size_ = static_cast<int>(size);
159 #if defined(_OPENMP)
160 #pragma omp parallel for
161 #endif
162  for (int i = 0; i < size_; ++i) {
163  float hue = hue_[i] / h_max;
164  float saturation = saturation_[i] / 255.f;
165  float value = value_[i] / 255.f;
166 
167  if (vpMath::equal(saturation, 0.f, std::numeric_limits<float>::epsilon())) {
168  hue = value;
169  saturation = value;
170  }
171  else {
172  float h = hue * 6.f;
173  float s = saturation;
174  float v = value;
175 
176  if (vpMath::equal(h, 6.f, std::numeric_limits<float>::epsilon())) {
177  h = 0.0f;
178  }
179  float f = h - static_cast<int>(h);
180  float p = v * (1.0f - s);
181  float q = v * (1.0f - (s * f));
182  float t = v * (1.0f - (s * (1.0f - f)));
183 
184  switch (static_cast<int>(h)) {
185  case 0:
186  hue = v;
187  saturation = t;
188  value = p;
189  break;
190 
191  case 1:
192  hue = q;
193  saturation = v;
194  value = p;
195  break;
196 
197  case 2:
198  hue = p;
199  saturation = v;
200  value = t;
201  break;
202 
203  case 3:
204  hue = p;
205  saturation = q;
206  value = v;
207  break;
208 
209  case 4:
210  hue = t;
211  saturation = p;
212  value = v;
213  break;
214 
215  default: // case 5:
216  hue = v;
217  saturation = p;
218  value = q;
219  break;
220  }
221  }
222 
223  int i_step = i * step;
224  rgb[i_step] = static_cast<unsigned char>(hue * 255.f);
225  rgb[++i_step] = static_cast<unsigned char>(saturation * 255.0f);
226  rgb[++i_step] = static_cast<unsigned char>(value * 255.0f);
227  if ((++i_step) == 3) { // alpha
228  rgb[i_step] = vpRGBa::alpha_default;
229  }
230  }
231 }
232 
246 void vpImageConvert::RGB2HSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
247  unsigned int size, unsigned int step)
248 {
249  int size_ = static_cast<int>(size);
250 #if defined(_OPENMP)
251 #pragma omp parallel for
252 #endif
253  for (int i = 0; i < size_; ++i) {
254  double red, green, blue;
255  double h, s, v;
256  double min, max;
257  int i_ = i * step;
258 
259  red = rgb[i_] / 255.0;
260  green = rgb[++i_] / 255.0;
261  blue = rgb[++i_] / 255.0;
262 
263  if (red > green) {
264  max = std::max<double>(red, blue);
265  min = std::min<double>(green, blue);
266  }
267  else {
268  max = std::max<double>(green, blue);
269  min = std::min<double>(red, blue);
270  }
271 
272  v = max;
273 
274  if (!vpMath::equal(max, 0.0, std::numeric_limits<double>::epsilon())) {
275  s = (max - min) / max;
276  }
277  else {
278  s = 0.0;
279  }
280 
281  if (vpMath::equal(s, 0.0, std::numeric_limits<double>::epsilon())) {
282  h = 0.0;
283  }
284  else {
285  double delta = max - min;
286 
287  if (vpMath::equal(red, max, std::numeric_limits<double>::epsilon())) {
288  h = (green - blue) / delta;
289  }
290  else if (vpMath::equal(green, max, std::numeric_limits<double>::epsilon())) {
291  h = 2 + ((blue - red) / delta);
292  }
293  else {
294  h = 4 + ((red - green) / delta);
295  }
296 
297  h /= 6.0;
298  if (h < 0.0) {
299  h += 1.0;
300  }
301  else if (h > 1.0) {
302  h -= 1.0;
303  }
304  }
305 
306  hue[i] = h;
307  saturation[i] = s;
308  value[i] = v;
309  }
310 }
311 
326 void vpImageConvert::RGB2HSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation, unsigned char *value,
327  unsigned int size, unsigned int step, bool h_full)
328 {
329  int size_ = static_cast<int>(size);
330  std::vector<float> h_scale(4);
331  if (h_full) {
332  h_scale[0] = 42.5f;
333  h_scale[1] = 85.f;
334  h_scale[2] = 170.f;
335  h_scale[3] = 255.f;
336  }
337  else {
338  h_scale[0] = 30.f;
339  h_scale[1] = 60.f;
340  h_scale[2] = 120.f;
341  h_scale[3] = 180.f;
342  }
343 #if defined(_OPENMP)
344 #pragma omp parallel for
345 #endif
346  for (int i = 0; i < size_; ++i) {
347  float red, green, blue;
348  float h, s, v;
349  float min, max;
350  unsigned int i_ = i * step;
351 
352  red = rgb[i_];
353  green = rgb[++i_];
354  blue = rgb[++i_];
355 
356  if (red > green) {
357  max = std::max<float>(red, blue);
358  min = std::min<float>(green, blue);
359  }
360  else {
361  max = std::max<float>(green, blue);
362  min = std::min<float>(red, blue);
363  }
364 
365  v = max;
366 
367  if (!vpMath::equal(max, 0.f, std::numeric_limits<float>::epsilon())) {
368  s = (255.f * (max - min)) / max;
369  }
370  else {
371  s = 0.f;
372  }
373 
374  if (vpMath::equal(s, 0.f, std::numeric_limits<float>::epsilon())) {
375  h = 0.f;
376  }
377  else {
378  float delta = max - min;
379 
380  if (vpMath::equal(red, max, std::numeric_limits<float>::epsilon())) {
381  h = (h_scale[0] * (green - blue)) / delta;
382  }
383  else if (vpMath::equal(green, max, std::numeric_limits<float>::epsilon())) {
384  h = h_scale[1] + ((h_scale[0] * (blue - red)) / delta);
385  }
386  else {
387  h = h_scale[2] + ((h_scale[0] * (red - green)) / delta);
388  }
389 
390  if (h < 0.f) {
391  h += h_scale[3];
392  }
393  }
394 
395  hue[i] = static_cast<unsigned char>(h);
396  saturation[i] = static_cast<unsigned char>(s);
397  value[i] = static_cast<unsigned char>(v);
398  }
399 }
400 
414 void vpImageConvert::HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba,
415  unsigned int size)
416 {
417  vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, 4);
418 }
419 
434 void vpImageConvert::HSVToRGBa(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
435  unsigned char *rgba, unsigned int size, bool h_full)
436 {
437  vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, 4, h_full);
438 }
439 
453 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value,
454  unsigned int size)
455 {
456  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, 4);
457 }
458 
475 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, unsigned char *hue, unsigned char *saturation,
476  unsigned char *value, unsigned int size, bool h_full)
477 {
478  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, 4, h_full);
479 }
480 
494 void vpImageConvert::HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb,
495  unsigned int size)
496 {
497  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, 3);
498 }
499 
514 void vpImageConvert::HSVToRGB(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
515  unsigned char *rgb, unsigned int size, bool h_full)
516 {
517  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, 3, h_full);
518 }
519 
532 void vpImageConvert::RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
533  unsigned int size)
534 {
535  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, 3);
536 }
537 
553 void vpImageConvert::RGBToHSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation,
554  unsigned char *value, unsigned int size, bool h_full)
555 {
556  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, 3, h_full);
557 }
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:449
static int round(double x)
Definition: vpMath.h:403
@ alpha_default
Definition: vpRGBa.h:63