Visual Servoing Platform  version 3.6.1 under development (2024-06-20)
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 
60 void vpImageConvert::HSV2RGB(const double *hue_, const double *saturation_, const double *value_, unsigned char *rgb,
61  unsigned int size, unsigned int step)
62 {
63  int size_ = static_cast<int>(size);
64 #if defined(_OPENMP)
65 #pragma omp parallel for
66 #endif
67  for (int i = 0; i < size_; ++i) {
68  double hue = hue_[i], saturation = saturation_[i], value = value_[i];
69 
70  if (vpMath::equal(saturation, 0.0, std::numeric_limits<double>::epsilon())) {
71  hue = value;
72  saturation = value;
73  }
74  else {
75  double h = hue * 6.0;
76  double s = saturation;
77  double v = value;
78 
79  if (vpMath::equal(h, 6.0, std::numeric_limits<double>::epsilon())) {
80  h = 0.0;
81  }
82 
83  double f = h - static_cast<int>(h);
84  double p = v * (1.0 - s);
85  double q = v * (1.0 - (s * f));
86  double t = v * (1.0 - (s * (1.0 - f)));
87 
88  switch (static_cast<int>(h)) {
89  case 0:
90  hue = v;
91  saturation = t;
92  value = p;
93  break;
94 
95  case 1:
96  hue = q;
97  saturation = v;
98  value = p;
99  break;
100 
101  case 2:
102  hue = p;
103  saturation = v;
104  value = t;
105  break;
106 
107  case 3:
108  hue = p;
109  saturation = q;
110  value = v;
111  break;
112 
113  case 4:
114  hue = t;
115  saturation = p;
116  value = v;
117  break;
118 
119  default: // case 5:
120  hue = v;
121  saturation = p;
122  value = q;
123  break;
124  }
125  }
126 
127  int i_step = i * step;
128  rgb[i_step] = static_cast<unsigned char>(vpMath::round(hue * 255.0));
129  rgb[++i_step] = static_cast<unsigned char>(vpMath::round(saturation * 255.0));
130  rgb[++i_step] = static_cast<unsigned char>(vpMath::round(value * 255.0));
131  if ((++i_step) == 3) { // alpha
132  rgb[i_step] = vpRGBa::alpha_default;
133  }
134  }
135 }
136 
149 void vpImageConvert::HSV2RGB(const unsigned char *hue_, const unsigned char *saturation_, const unsigned char *value_,
150  unsigned char *rgb, unsigned int size, unsigned int step, bool h_full)
151 {
152  float h_max;
153  if (h_full) {
154  h_max = 255.f;
155  }
156  else {
157  h_max = 180.f;
158  }
159  int size_ = static_cast<int>(size);
160 #if defined(_OPENMP)
161 #pragma omp parallel for
162 #endif
163  for (int i = 0; i < size_; ++i) {
164  float hue = hue_[i] / h_max;
165  float saturation = saturation_[i] / 255.f;
166  float value = value_[i] / 255.f;
167 
168  if (vpMath::equal(saturation, 0.f, std::numeric_limits<float>::epsilon())) {
169  hue = value;
170  saturation = value;
171  }
172  else {
173  float h = hue * 6.f;
174  float s = saturation;
175  float v = value;
176 
177  if (vpMath::equal(h, 6.f, std::numeric_limits<float>::epsilon())) {
178  h = 0.0f;
179  }
180  float f = h - static_cast<int>(h);
181  float p = v * (1.0f - s);
182  float q = v * (1.0f - (s * f));
183  float t = v * (1.0f - (s * (1.0f - f)));
184 
185  switch (static_cast<int>(h)) {
186  case 0:
187  hue = v;
188  saturation = t;
189  value = p;
190  break;
191 
192  case 1:
193  hue = q;
194  saturation = v;
195  value = p;
196  break;
197 
198  case 2:
199  hue = p;
200  saturation = v;
201  value = t;
202  break;
203 
204  case 3:
205  hue = p;
206  saturation = q;
207  value = v;
208  break;
209 
210  case 4:
211  hue = t;
212  saturation = p;
213  value = v;
214  break;
215 
216  default: // case 5:
217  hue = v;
218  saturation = p;
219  value = q;
220  break;
221  }
222  }
223 
224  int i_step = i * step;
225  rgb[i_step] = static_cast<unsigned char>(hue * 255.f);
226  rgb[++i_step] = static_cast<unsigned char>(saturation * 255.0f);
227  rgb[++i_step] = static_cast<unsigned char>(value * 255.0f);
228  if ((++i_step) == 3) { // alpha
229  rgb[i_step] = vpRGBa::alpha_default;
230  }
231  }
232 }
233 
247 void vpImageConvert::RGB2HSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
248  unsigned int size, unsigned int step)
249 {
250  int size_ = static_cast<int>(size);
251 #if defined(_OPENMP)
252 #pragma omp parallel for
253 #endif
254  for (int i = 0; i < size_; ++i) {
255  double red, green, blue;
256  double h, s, v;
257  double min, max;
258  int i_ = i * step;
259 
260  red = rgb[i_] / 255.0;
261  green = rgb[++i_] / 255.0;
262  blue = rgb[++i_] / 255.0;
263 
264  if (red > green) {
265  max = std::max<double>(red, blue);
266  min = std::min<double>(green, blue);
267  }
268  else {
269  max = std::max<double>(green, blue);
270  min = std::min<double>(red, blue);
271  }
272 
273  v = max;
274 
275  if (!vpMath::equal(max, 0.0, std::numeric_limits<double>::epsilon())) {
276  s = (max - min) / max;
277  }
278  else {
279  s = 0.0;
280  }
281 
282  if (vpMath::equal(s, 0.0, std::numeric_limits<double>::epsilon())) {
283  h = 0.0;
284  }
285  else {
286  double delta = max - min;
287 
288  if (vpMath::equal(red, max, std::numeric_limits<double>::epsilon())) {
289  h = (green - blue) / delta;
290  }
291  else if (vpMath::equal(green, max, std::numeric_limits<double>::epsilon())) {
292  h = 2 + ((blue - red) / delta);
293  }
294  else {
295  h = 4 + ((red - green) / delta);
296  }
297 
298  h /= 6.0;
299  if (h < 0.0) {
300  h += 1.0;
301  }
302  else if (h > 1.0) {
303  h -= 1.0;
304  }
305  }
306 
307  hue[i] = h;
308  saturation[i] = s;
309  value[i] = v;
310  }
311 }
312 
327 void vpImageConvert::RGB2HSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation, unsigned char *value,
328  unsigned int size, unsigned int step, bool h_full)
329 {
330  int size_ = static_cast<int>(size);
331  std::vector<float> h_scale(4);
332  if (h_full) {
333  h_scale[0] = 42.5f;
334  h_scale[1] = 85.f;
335  h_scale[2] = 170.f;
336  h_scale[3] = 255.f;
337  }
338  else {
339  h_scale[0] = 30.f;
340  h_scale[1] = 60.f;
341  h_scale[2] = 120.f;
342  h_scale[3] = 180.f;
343  }
344 #if defined(_OPENMP)
345 #pragma omp parallel for
346 #endif
347  for (int i = 0; i < size_; ++i) {
348  float red, green, blue;
349  float h, s, v;
350  float min, max;
351  unsigned int i_ = i * step;
352 
353  red = rgb[i_];
354  green = rgb[++i_];
355  blue = rgb[++i_];
356 
357  if (red > green) {
358  max = std::max<float>(red, blue);
359  min = std::min<float>(green, blue);
360  }
361  else {
362  max = std::max<float>(green, blue);
363  min = std::min<float>(red, blue);
364  }
365 
366  v = max;
367 
368  if (!vpMath::equal(max, 0.f, std::numeric_limits<float>::epsilon())) {
369  s = (255.f * (max - min)) / max;
370  }
371  else {
372  s = 0.f;
373  }
374 
375  if (vpMath::equal(s, 0.f, std::numeric_limits<float>::epsilon())) {
376  h = 0.f;
377  }
378  else {
379  float delta = max - min;
380 
381  if (vpMath::equal(red, max, std::numeric_limits<float>::epsilon())) {
382  h = (h_scale[0] * (green - blue)) / delta;
383  }
384  else if (vpMath::equal(green, max, std::numeric_limits<float>::epsilon())) {
385  h = h_scale[1] + ((h_scale[0] * (blue - red)) / delta);
386  }
387  else {
388  h = h_scale[2] + ((h_scale[0] * (red - green)) / delta);
389  }
390 
391  if (h < 0.f) {
392  h += h_scale[3];
393  }
394  }
395 
396  hue[i] = static_cast<unsigned char>(h);
397  saturation[i] = static_cast<unsigned char>(s);
398  value[i] = static_cast<unsigned char>(v);
399  }
400 }
401 
415 void vpImageConvert::HSVToRGBa(const double *hue, const double *saturation, const double *value, unsigned char *rgba,
416  unsigned int size)
417 {
418  vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, 4);
419 }
420 
435 void vpImageConvert::HSVToRGBa(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
436  unsigned char *rgba, unsigned int size, bool h_full)
437 {
438  vpImageConvert::HSV2RGB(hue, saturation, value, rgba, size, 4, h_full);
439 }
440 
454 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, double *hue, double *saturation, double *value,
455  unsigned int size)
456 {
457  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, 4);
458 }
459 
476 void vpImageConvert::RGBaToHSV(const unsigned char *rgba, unsigned char *hue, unsigned char *saturation,
477  unsigned char *value, unsigned int size, bool h_full)
478 {
479  vpImageConvert::RGB2HSV(rgba, hue, saturation, value, size, 4, h_full);
480 }
481 
495 void vpImageConvert::HSVToRGB(const double *hue, const double *saturation, const double *value, unsigned char *rgb,
496  unsigned int size)
497 {
498  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, 3);
499 }
500 
515 void vpImageConvert::HSVToRGB(const unsigned char *hue, const unsigned char *saturation, const unsigned char *value,
516  unsigned char *rgb, unsigned int size, bool h_full)
517 {
518  vpImageConvert::HSV2RGB(hue, saturation, value, rgb, size, 3, h_full);
519 }
520 
533 void vpImageConvert::RGBToHSV(const unsigned char *rgb, double *hue, double *saturation, double *value,
534  unsigned int size)
535 {
536  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, 3);
537 }
538 
554 void vpImageConvert::RGBToHSV(const unsigned char *rgb, unsigned char *hue, unsigned char *saturation,
555  unsigned char *value, unsigned int size, bool h_full)
556 {
557  vpImageConvert::RGB2HSV(rgb, hue, saturation, value, size, 3, h_full);
558 }
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:456
static int round(double x)
Definition: vpMath.h:407
@ alpha_default
Definition: vpRGBa.h:65