Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
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 
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  const unsigned int index_0 = 0;
332  const unsigned int index_1 = 1;
333  const unsigned int index_2 = 2;
334  const unsigned int index_3 = 3;
335  if (h_full) {
336  h_scale[index_0] = 42.5f;
337  h_scale[index_1] = 85.f;
338  h_scale[index_2] = 170.f;
339  h_scale[index_3] = 255.f;
340  }
341  else {
342  h_scale[index_0] = 30.f;
343  h_scale[index_1] = 60.f;
344  h_scale[index_2] = 120.f;
345  h_scale[index_3] = 180.f;
346  }
347 #if defined(_OPENMP)
348 #pragma omp parallel for
349 #endif
350  for (int i = 0; i < size_; ++i) {
351  float red, green, blue;
352  float h, s, v;
353  float min, max;
354  unsigned int i_ = i * step;
355 
356  red = rgb[i_];
357  green = rgb[++i_];
358  blue = rgb[++i_];
359 
360  if (red > green) {
361  max = std::max<float>(red, blue);
362  min = std::min<float>(green, blue);
363  }
364  else {
365  max = std::max<float>(green, blue);
366  min = std::min<float>(red, blue);
367  }
368 
369  v = max;
370 
371  if (!vpMath::equal(max, 0.f, std::numeric_limits<float>::epsilon())) {
372  s = (255.f * (max - min)) / max;
373  }
374  else {
375  s = 0.f;
376  }
377 
378  if (vpMath::equal(s, 0.f, std::numeric_limits<float>::epsilon())) {
379  h = 0.f;
380  }
381  else {
382  float delta = max - min;
383 
384  if (vpMath::equal(red, max, std::numeric_limits<float>::epsilon())) {
385  h = (h_scale[index_0] * (green - blue)) / delta;
386  }
387  else if (vpMath::equal(green, max, std::numeric_limits<float>::epsilon())) {
388  h = h_scale[index_1] + ((h_scale[index_0] * (blue - red)) / delta);
389  }
390  else {
391  h = h_scale[index_2] + ((h_scale[index_0] * (red - green)) / delta);
392  }
393 
394  if (h < 0.f) {
395  h += h_scale[index_3];
396  }
397  }
398 
399  hue[i] = static_cast<unsigned char>(h);
400  saturation[i] = static_cast<unsigned char>(s);
401  value[i] = static_cast<unsigned char>(v);
402  }
403 }
404 
418 void vpImageConvert::HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba,
419  unsigned int size)
420 {
421  vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, 4);
422 }
423 
438 void vpImageConvert::HSVToRGBa(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
439  unsigned char *rgba, unsigned int size, bool h_full)
440 {
441  vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, 4, h_full);
442 }
443 
457 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value,
458  unsigned int size)
459 {
460  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, 4);
461 }
462 
479 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, unsigned char *hue, unsigned char *saturation,
480  unsigned char *value, unsigned int size, bool h_full)
481 {
482  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, 4, h_full);
483 }
484 
498 void vpImageConvert::HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb,
499  unsigned int size)
500 {
501  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, 3);
502 }
503 
518 void vpImageConvert::HSVToRGB(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
519  unsigned char *rgb, unsigned int size, bool h_full)
520 {
521  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, 3, h_full);
522 }
523 
536 void vpImageConvert::RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
537  unsigned int size)
538 {
539  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, 3);
540 }
541 
557 void vpImageConvert::RGBToHSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation,
558  unsigned char *value, unsigned int size, bool h_full)
559 {
560  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, 3, h_full);
561 }
562 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:458
static int round(double x)
Definition: vpMath.h:409
@ alpha_default
Definition: vpRGBa.h:67