Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpHSV.h
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 * HSV color scale.
32 */
33
34#ifndef VP_HSV_H
35#define VP_HSV_H
36
37#include <exception>
38#include <iostream>
39#include <limits>
40#include <sstream>
41#include <string>
42
43#include <visp3/core/vpConfig.h>
44#include <visp3/core/vpColVector.h>
45#include <visp3/core/vpMath.h>
46#include <visp3/core/vpRGBa.h>
47
48#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
49#include <type_traits>
50
52template<typename T, bool = true>
53class vpHSV;
54
55template <typename T, bool useFullScale>
56std::ostream &operator<<(std::ostream &os, const vpHSV<T, useFullScale> &hsv);
57
58#ifndef VISP_PYTHON_PREPROCESSOR_RUNNING
59namespace
60{
69template <typename T, bool otherUseFullScale, typename EnableIf = void>
70struct UniformLawVariance;
71
80template <typename T, bool useFullScale>
81struct UniformLawVariance<T, useFullScale, typename std::enable_if<std::is_floating_point<T>::value>::type>
82{
83 // Variance of a continuous uniform law defined on the intervall [a; b] = (b - a)^2 / 12
84 // Here, a = 0, b = 1
85 static constexpr float hueVariance = 1.f/12.f;
86 static constexpr float otherChannelsVariance = 1.f/12.f;
87};
88
93template <>
94struct UniformLawVariance<unsigned char, true>
95{
96 // Variance of a discrete uniform law defined on the intervall {a; a + 1; ... b} = ((b - a + 1)^2 - 1)/ 12
97 // Here, a = 0, b = 255
98 static constexpr float hueVariance = (256.f * 256.f - 1.f)/12.f;
99 static constexpr float otherChannelsVariance = (256.f * 256.f - 1.f)/12.f;
100};
101
107template <>
108struct UniformLawVariance<unsigned char, false>
109{
110 // Variance of a discrete uniform law defined on the intervall {a; a + 1; ... b} = ((b - a + 1)^2 - 1)/ 12
111 // Here, a = 0, b = 255 for the Saturation and Value channels
112 // and {0; 1; ...; maxHueUsingLimitedRange} for the Hue channel.
113 static constexpr float hueVariance = (180.f * 180.f - 1.f)/12.f;
114 static constexpr float otherChannelsVariance = (256.f * 256.f - 1.f)/12.f;
115};
116}
117#endif
118
133template<typename T, bool useFullScale>
134class vpHSV
135{
136public:
145 explicit vpHSV(const double &H_ = 0., const double &S_ = 0., const double &V_ = 0.)
146 : H(static_cast<T>(H_))
147 , S(static_cast<T>(S_))
148 , V(static_cast<T>(V_))
149 { }
150
158 {
159 this->set(v);
160 }
161
165 vpHSV(const vpHSV<T, useFullScale> &) = default;
166
167#ifndef VISP_PYTHON_PREPROCESSOR_RUNNING
178 template<typename U = T, typename V, typename std::enable_if<std::is_same<T, unsigned char>::value &&std::is_floating_point<V>::value &&useFullScale, U>::type = 0 >
179 vpHSV(const vpHSV<V> &other)
180 {
181 buildFrom(other);
182 }
183
194 template<typename U = T, typename V, typename std::enable_if<std::is_same<T, unsigned char>::value &&std::is_floating_point<V>::value && !useFullScale, U>::type = 0 >
195 vpHSV(const vpHSV<V> &other)
196 {
197 buildFrom(other);
198 }
199
209 template<typename U = T, bool otherUseFullScale, typename std::enable_if<std::is_floating_point<U>::value>::type...>
211 {
212 buildFrom(other);
213 }
214#endif
215
221 vpHSV(const vpRGBa &rgba)
222 {
223 buildFrom(rgba);
224 }
225
229#if (VISP_CXX_STANDARD > VISP_CXX_STANDARD_98)
230 virtual ~vpHSV() = default;
231#else
232 virtual ~vpHSV() { }
233#endif
234
242
253 template<typename V, bool otherUseFullScale>
254 typename std::enable_if<std::is_same<T, unsigned char>::value &&std::is_floating_point<V>::value &&useFullScale, vpHSV<T, useFullScale> &>::type
256 {
257 H = static_cast<T>(other.H * 255.);
258 S = static_cast<T>(other.S * 255.);
259 this->V = static_cast<T>(other.V * 255.);
260 return *this;
261 }
262
273 template<typename U = T, typename V, bool otherUseFullScale>
274 typename std::enable_if<std::is_same<U, unsigned char>::value &&std::is_floating_point<V>::value && !useFullScale, vpHSV<T, useFullScale> &>::type
276 {
277 H = static_cast<T>(other.H * static_cast<double>(maxHueUsingLimitedRange));
278 S = static_cast<T>(other.S * 255.);
279 this->V = static_cast<T>(other.V * 255.);
280 return *this;
281 }
282
293 template<typename U = T, bool otherUseFullScale>
294 typename std::enable_if<std::is_floating_point<U>::value, vpHSV<T, useFullScale> &>::type
296 {
297 if (otherUseFullScale) {
298 H = static_cast<T>(other.H) / static_cast<T>(255.);
299 }
300 else {
301 H = static_cast<T>(other.H) / static_cast<T>(maxHueUsingLimitedRange);
302 }
303 S = static_cast<T>(other.S) / static_cast<T>(255.);
304 V = static_cast<T>(other.V) / static_cast<T>(255.);
305 return *this;
306 }
307
321 template<typename U = T, typename V, bool otherUseFullScale>
322 typename std::enable_if<std::is_floating_point<U>::value &&std::is_floating_point<V>::value && !std::is_same<T, V>::value, vpHSV<T, useFullScale> &>::type
324 {
325 H = static_cast<T>(other.H);
326 S = static_cast<T>(other.S);
327 this->V = static_cast<T>(other.V);
328 return *this;
329 }
330
338 {
339 double red, green, blue;
340 double h, s, v;
341 double min, max;
342
343 red = rgba.R / 255.0;
344 green = rgba.G / 255.0;
345 blue = rgba.B / 255.0;
346
347 if (red > green) {
348 max = std::max<double>(red, blue);
349 min = std::min<double>(green, blue);
350 }
351 else {
352 max = std::max<double>(green, blue);
353 min = std::min<double>(red, blue);
354 }
355
356 v = max;
357
358 if (!vpMath::equal(max, 0.0, std::numeric_limits<double>::epsilon())) {
359 s = (max - min) / max;
360 }
361 else {
362 s = 0.0;
363 }
364
365 if (vpMath::equal(s, 0.0, std::numeric_limits<double>::epsilon())) {
366 h = 0.0;
367 }
368 else {
369 double delta = max - min;
370
371 if (vpMath::equal(red, max, std::numeric_limits<double>::epsilon())) {
372 h = (green - blue) / delta;
373 }
374 else if (vpMath::equal(green, max, std::numeric_limits<double>::epsilon())) {
375 h = 2.0 + ((blue - red) / delta);
376 }
377 else {
378 h = 4.0 + ((red - green) / delta);
379 }
380
381 h /= 6.0;
382 if (h < 0.0) {
383 h += 1.0;
384 }
385 else if (h > 1.0) {
386 h -= 1.0;
387 }
388 }
389
390 vpColVector hsv(3);
391 hsv[0] = h;
392 hsv[1] = s;
393 hsv[2] = v;
394 return hsv;
395 }
396
406 template <typename ArithmeticType>
407 inline static ArithmeticType squaredMahalanobisDistance(const vpHSV<T, useFullScale> &a, const vpHSV<T, useFullScale> &b, vpColVector &diff)
408 {
409 static const ArithmeticType invHueVariance = 1.f / UniformLawVariance<T, useFullScale>::hueVariance;
410 static const ArithmeticType invOtherChannelsVariance = 1.f / UniformLawVariance<T, useFullScale>::otherChannelsVariance;
411 diff.resize(3);
412 diff[0] = b.H - a.H;
413 diff[1] = b.S - a.S;
414 diff[2] = b.V - a.V;
415 ArithmeticType distance = diff[0] * diff[0] * invHueVariance + invOtherChannelsVariance * (diff[1] * diff[1] + diff[2] * diff[2]);
416 return distance;
417 }
418
427 template <typename ArithmeticType>
428 inline static ArithmeticType squaredMahalanobisDistance(const vpHSV<T, useFullScale> &a, const vpHSV<T, useFullScale> &b)
429 {
430 vpColVector diff;
432 }
433
442 template <typename ArithmeticType>
443 inline static ArithmeticType mahalanobisDistance(const vpHSV<T, useFullScale> &a, const vpHSV<T, useFullScale> &b)
444 {
445 return std::sqrt(squaredMahalanobisDistance<ArithmeticType>(a, b));
446 }
447
457 template <typename ArithmeticType>
458 inline static ArithmeticType mahalanobisDistance(const vpHSV<T, useFullScale> &a, const vpHSV<T, useFullScale> &b, vpColVector &diff)
459 {
460 return std::sqrt(squaredMahalanobisDistance<ArithmeticType>(a, b, diff));
461 }
462
463 // Operators
466
468 {
469 vpHSV<T, useFullScale> vAsHSV(v);
470 *this = vAsHSV;
471 return *this;
472 }
473
474
476 {
477 return(vpMath::equal(v.H, H, 1e-6) && vpMath::equal(v.S, S, 1e-6) && vpMath::equal(v.V, V, 1e-6));
478 }
479
481 {
482 return !(*this == v);
483 }
484
486 {
487 return this->toColVector() - v.toColVector();
488 }
489
491 {
493 result.H = H + v.H;
494 result.S = S + v.S;
495 result.V = V + v.V;
496 return result;
497 }
498
500 {
501 return this->toColVector() - v;
502 }
503
505 {
506 vpColVector result(3);
507 result[0] = H + v[0];
508 result[1] = S + v[1];
509 result[2] = V + v[2];
510 return result;
511 }
512
519 {
520 vpColVector color(3);
521 color[0] = H;
522 color[1] = S;
523 color[2] = V;
524 return color;
525 }
526
532 virtual std::string toString() const;
533
534 friend std::ostream &operator<< <>(std::ostream &os, const vpHSV<T, useFullScale> &hsv);
535
536public:
537 T H;
538 T S;
539 T V;
540
544 static constexpr unsigned char nbChannels = 3;
545
549 static constexpr unsigned char maxHueUsingLimitedRange = 179;
550
551private:
561 template<typename Tp = T>
562 inline
563 typename std::enable_if<std::is_floating_point<Tp>::value, void>::type set(const vpColVector &v)
564 {
565 // const Tp limMin = 0.;
566 // const Tp limMax = 1.;
567 // if ((v[0] < limMin) || (v[0] > limMax)) {
568 // // throw exception
569 // }
570 H = v[0];
571 // if ((v[1] < limMin) || (v[1] > limMax)) {
572 // // throw exception
573 // }
574 S = v[1];
575 // if ((v[2] < limMin) || (v[2] > limMax)) {
576 // // throw exception
577 // }
578 V = v[2];
579 }
580
581 template<typename Tp = T>
582 inline
583 typename std::enable_if<std::is_same<Tp, unsigned char>::value, void>::type set(const vpColVector &v)
584 {
585 // const Tp otherMax = std::numeric_limits<U>::max();
586 // Tp hmax;
587 // if (useFullScale) {
588 // hmax = std::numeric_limits<U>::max();
589 // }
590 // else {
591 // hmax = maxHueUsingLimitedRange;
592 // }
593
594 // if (v[0] > hmax) {
595 // // throw exception
596 // }
597 H = static_cast<T>(v[0]);
598
599 // if (v[1] > otherMax) {
600 // // throw exception
601 // }
602 S = static_cast<T>(v[1]);
603
604 // if (v[2] > otherMax) {
605 // // throw exception
606 // }
607 V = static_cast<T>(v[2]);
608 }
609};
610
611template <typename T, bool useFullScale>
613{
614 std::stringstream ss;
615 ss << "vpHSV<";
616 using CastType = typename std::conditional<std::is_integral<T>::value, int, T>::type;
617 if (std::is_same<T, unsigned char>::value) {
618 ss << "uchar";
619 }
620 else if (std::is_same<T, double>::value) {
621 ss << "double";
622 }
623 else {
624 ss << "other";
625 }
626
627 if (useFullScale) {
628 std::cout << ", full";
629 }
630 else {
631 std::cout << ", partial";
632 }
633 ss << " scale> (H, S, V): (" << (CastType)H << " , " << (CastType)S << " , " << (CastType)V << ")";
634 return ss.str();
635}
636
637template <typename T, bool useFullScale>
638std::ostream &operator<<(std::ostream &os, const vpHSV<T, useFullScale> &hsv)
639{
640 os << hsv.toString();
641 return os;
642}
643
644template<>
646
647template<>
649
650template<>
652
653END_VISP_NAMESPACE
654#endif
655#endif
Implementation of column vector and the associated operations.
void resize(unsigned int i, bool flagNullify=true)
Class implementing the HSV pixel format.
Definition vpHSV.h:135
bool operator==(const vpHSV< T, useFullScale > &v) const
Definition vpHSV.h:475
vpHSV< T, useFullScale > & operator=(const vpColVector &v)
Definition vpHSV.h:467
T V
Definition vpHSV.h:539
std::enable_if< std::is_floating_point< U >::value, vpHSV< T, useFullScale > & >::type buildFrom(const vpHSV< unsigned char, otherUseFullScale > &other)
Convert a vpHSV that uses unsigned char for its channels into a vpHSV that uses floating point for it...
Definition vpHSV.h:295
vpHSV(const vpRGBa &rgba)
Construct a new vpHSV object from a vpRGBa object.
Definition vpHSV.h:221
vpHSV< T, useFullScale > operator+(const vpHSV< T, useFullScale > &v) const
Definition vpHSV.h:490
vpColVector operator-(const vpColVector &v) const
Definition vpHSV.h:499
virtual std::string toString() const
Cast a vpHSV into a string, for display purpose.
Definition vpHSV.h:612
std::enable_if< std::is_same< T, unsignedchar >::value &&std::is_floating_point< V >::value &&useFullScale, vpHSV< T, useFullScale > & >::type buildFrom(const vpHSV< V, otherUseFullScale > &other)
Convert a floating point HSV into a unsigned char HSV using the full range [0; 255].
Definition vpHSV.h:255
vpColVector toColVector() const
Cast a vpHSV into a vpColVector.
Definition vpHSV.h:518
vpHSV(const double &H_=0., const double &S_=0., const double &V_=0.)
Construct a new vpHSV object using floating point channels.
Definition vpHSV.h:145
std::enable_if< std::is_floating_point< U >::value &&std::is_floating_point< V >::value &&!std::is_same< T, V >::value, vpHSV< T, useFullScale > & >::type buildFrom(const vpHSV< V, otherUseFullScale > &other)
Convert a floating point HSV into another floating point type HSV.
Definition vpHSV.h:323
static ArithmeticType mahalanobisDistance(const vpHSV< T, useFullScale > &a, const vpHSV< T, useFullScale > &b, vpColVector &diff)
Compute the Mahalanobis distance between two HSV pixels. It is assumed that the channels are independ...
Definition vpHSV.h:458
bool operator!=(const vpHSV< T, useFullScale > &v) const
Definition vpHSV.h:480
T S
Definition vpHSV.h:538
static ArithmeticType squaredMahalanobisDistance(const vpHSV< T, useFullScale > &a, const vpHSV< T, useFullScale > &b, vpColVector &diff)
Compute the square of the Mahalanobis distance between two HSV pixels. It is assumed that the channel...
Definition vpHSV.h:407
static vpColVector computeNormalizedHSV(const vpRGBa &rgba)
Compute the normalized HSV values (i.e. in the range [0; 1]) that correspond to a vpRGBa object.
Definition vpHSV.h:337
static ArithmeticType squaredMahalanobisDistance(const vpHSV< T, useFullScale > &a, const vpHSV< T, useFullScale > &b)
Compute the square of the Mahalanobis distance between two HSV pixels. It is assumed that the channel...
Definition vpHSV.h:428
vpHSV(const vpHSV< unsigned char, otherUseFullScale > &other)
Construct a new floating point vpHSV object from an unsigned char vpHSV object.
Definition vpHSV.h:210
static ArithmeticType mahalanobisDistance(const vpHSV< T, useFullScale > &a, const vpHSV< T, useFullScale > &b)
Compute the Mahalanobis distance between two HSV pixels. It is assumed that the channels are independ...
Definition vpHSV.h:443
static constexpr unsigned char nbChannels
Number of channels a HSV pixel is made of.
Definition vpHSV.h:544
vpColVector operator-(const vpHSV< T, useFullScale > &v) const
Definition vpHSV.h:485
virtual ~vpHSV()=default
vpHSV(const vpHSV< V > &other)
Construct a new vpHSV object using unsigned char channels and the full range [0; 255] from a vpHSV ob...
Definition vpHSV.h:179
friend std::ostream & operator<<(std::ostream &os, const vpHSV< T, useFullScale > &hsv)
Definition vpHSV.h:638
std::enable_if< std::is_same< U, unsignedchar >::value &&std::is_floating_point< V >::value &&!useFullScale, vpHSV< T, useFullScale > & >::type buildFrom(const vpHSV< V, otherUseFullScale > &other)
Convert a floating point HSV into a unsigned char HSV using the limited range [0; maxHueUsingLimitedR...
Definition vpHSV.h:275
vpHSV(const vpColVector &v)
Construct a new vpHSV object from a vpColVector.
Definition vpHSV.h:157
vpHSV(const vpHSV< T, useFullScale > &)=default
Default copy constructor.
static constexpr unsigned char maxHueUsingLimitedRange
Maximum value of the Hue channel when using unsigned char and the limited range.
Definition vpHSV.h:549
T H
Definition vpHSV.h:537
vpColVector operator+(const vpColVector &v) const
Definition vpHSV.h:504
vpHSV< T, useFullScale > & operator=(vpHSV< T, useFullScale > &&)=default
vpHSV< T, useFullScale > & operator=(const vpHSV< T, useFullScale > &)=default
vpHSV< T, useFullScale > & buildFrom(const vpRGBa &rgba)
Modify the object to be the result of the conversion of the vpRGBa object into HSV format.
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:470
unsigned char B
Blue component.
Definition vpRGBa.h:327
unsigned char R
Red component.
Definition vpRGBa.h:325
unsigned char G
Green component.
Definition vpRGBa.h:326