Visual Servoing Platform  version 3.6.1 under development (2024-12-17)
vpImageConvert_hsv.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 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 *****************************************************************************/
34 
40 #if defined(_OPENMP)
41 #include <omp.h>
42 #endif
43 
44 #include <visp3/core/vpConfig.h>
45 #include <visp3/core/vpImageConvert.h>
46 
47 BEGIN_VISP_NAMESPACE
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  const int val_2 = 2;
88  const int val_3 = 3;
89  const int val_4 = 4;
90  switch (static_cast<int>(h)) {
91  case 0:
92  hue = v;
93  saturation = t;
94  value = p;
95  break;
96 
97  case 1:
98  hue = q;
99  saturation = v;
100  value = p;
101  break;
102 
103  case val_2:
104  hue = p;
105  saturation = v;
106  value = t;
107  break;
108 
109  case val_3:
110  hue = p;
111  saturation = q;
112  value = v;
113  break;
114 
115  case val_4:
116  hue = t;
117  saturation = p;
118  value = v;
119  break;
120 
121  default: // case 5:
122  hue = v;
123  saturation = p;
124  value = q;
125  break;
126  }
127  }
128 
129  int i_step = i * step;
130  rgb[i_step] = static_cast<unsigned char>(vpMath::round(hue * 255.0));
131  rgb[++i_step] = static_cast<unsigned char>(vpMath::round(saturation * 255.0));
132  rgb[++i_step] = static_cast<unsigned char>(vpMath::round(value * 255.0));
133  const int val_3 = 3;
134  if (i_step == val_3) { // alpha
135  ++i_step;
136  rgb[i_step] = vpRGBa::alpha_default;
137  }
138  }
139 }
140 
153 void vpImageConvert::HSV2RGB(const unsigned char *hue_, const unsigned char *saturation_, const unsigned char *value_,
154  unsigned char *rgb, unsigned int size, unsigned int step, bool h_full)
155 {
156  const int val_2 = 2;
157  const int val_3 = 3;
158  const int val_4 = 4;
159  float h_max;
160  if (h_full) {
161  h_max = 255.f;
162  }
163  else {
164  h_max = 180.f;
165  }
166  int size_ = static_cast<int>(size);
167 #if defined(_OPENMP)
168 #pragma omp parallel for
169 #endif
170  for (int i = 0; i < size_; ++i) {
171  float hue = hue_[i] / h_max;
172  float saturation = saturation_[i] / 255.f;
173  float value = value_[i] / 255.f;
174 
175  if (vpMath::equal(saturation, 0.f, std::numeric_limits<float>::epsilon())) {
176  hue = value;
177  saturation = value;
178  }
179  else {
180  float h = hue * 6.f;
181  float s = saturation;
182  float v = value;
183 
184  if (vpMath::equal(h, 6.f, std::numeric_limits<float>::epsilon())) {
185  h = 0.0f;
186  }
187  float f = h - static_cast<int>(h);
188  float p = v * (1.0f - s);
189  float q = v * (1.0f - (s * f));
190  float t = v * (1.0f - (s * (1.0f - f)));
191 
192  switch (static_cast<int>(h)) {
193  case 0:
194  hue = v;
195  saturation = t;
196  value = p;
197  break;
198 
199  case 1:
200  hue = q;
201  saturation = v;
202  value = p;
203  break;
204 
205  case val_2:
206  hue = p;
207  saturation = v;
208  value = t;
209  break;
210 
211  case val_3:
212  hue = p;
213  saturation = q;
214  value = v;
215  break;
216 
217  case val_4:
218  hue = t;
219  saturation = p;
220  value = v;
221  break;
222 
223  default: // case 5:
224  hue = v;
225  saturation = p;
226  value = q;
227  break;
228  }
229  }
230 
231  int i_step = i * step;
232  rgb[i_step] = static_cast<unsigned char>(hue * 255.f);
233  rgb[++i_step] = static_cast<unsigned char>(saturation * 255.0f);
234  rgb[++i_step] = static_cast<unsigned char>(value * 255.0f);
235  if (i_step == val_3) { // alpha
236  ++i_step;
237  rgb[i_step] = vpRGBa::alpha_default;
238  }
239  }
240 }
241 
255 void vpImageConvert::RGB2HSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
256  unsigned int size, unsigned int step)
257 {
258  int size_ = static_cast<int>(size);
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 
337 void 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_ = 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 
429 void 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 
450 void 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 
470 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value,
471  unsigned int size)
472 {
473  const unsigned int val_4 = 4;
474  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, val_4);
475 }
476 
493 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, unsigned char *hue, unsigned char *saturation,
494  unsigned char *value, unsigned int size, bool h_full)
495 {
496  const unsigned int val_4 = 4;
497  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, val_4, h_full);
498 }
499 
513 void vpImageConvert::HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb,
514  unsigned int size)
515 {
516  const unsigned int val_3 = 3;
517  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, val_3);
518 }
519 
534 void vpImageConvert::HSVToRGB(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
535  unsigned char *rgb, unsigned int size, bool h_full)
536 {
537  const unsigned int val_3 = 3;
538  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, val_3, h_full);
539 }
540 
553 void vpImageConvert::RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
554  unsigned int size)
555 {
556  const unsigned int val_3 = 3;
557  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, val_3);
558 }
559 
575 void vpImageConvert::RGBToHSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation,
576  unsigned char *value, unsigned int size, bool h_full)
577 {
578  const unsigned int val_3 = 3;
579  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, val_3, h_full);
580 }
581 END_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:459
static int round(double x)
Definition: vpMath.h:410
@ alpha_default
Definition: vpRGBa.h:67