In C++, an 8-bit RGB-to-HSV converter normalizes R, G, and B by dividing by 255.0, then computes value as the maximum, saturation as (maximum - minimum) / maximum when the maximum is nonzero, and hue from the maximal channel. The function below returns hue in degrees from 0 up to but not including 360, plus saturation and value as fractions from 0 to 1, making it reusable across applications with different output conventions.

convert rgb to hsv c++
Convert RGB to HSV in C++: Complete Code Example

Define the RGB and HSV contract

An 8-bit C++ interface should accept whole-number red, green, and blue channels from 0 through 255. HSV does not replace or approximate the RGB triplet; it reorganizes the same color so that hue, color intensity, and brightness can be handled separately.

Component Calculation Range Meaning
Hue Use the branch for the maximum RGB channel and wrap negative angles by adding 360 0–360 degrees Position around the color wheel
Saturation delta / maximum, with a separate zero result for black 0–1 Distance from the gray axis relative to value
Value Maximum normalized RGB channel 0–1 Strength of the strongest channel

Here, delta is the difference between the maximum and minimum normalized channels. It becomes zero when all three RGB channels are equal, which requires an explicit achromatic-color convention.

Build a complete C++ converter

The implementation uses only the C++ standard library and keeps the calculated values as double-precision numbers until display time.

  1. Accept red, green, and blue as integer parameters and reject values outside 0–255.
  2. Normalize each channel by 255.0, then find the maximum, minimum, and delta.
  3. Calculate value and saturation, guarding the black case where the maximum is zero.
  4. Calculate hue from the maximal channel and add 360 when the intermediate hue is negative.
  5. Return the unrounded result and format it only when writing to the output.

#include <algorithm>

#include <iomanip>

#include <iostream>

#include <stdexcept>

struct HSV {

double h; // degrees in [0, 360)

double s; // fraction in [0, 1]

double v; // fraction in [0, 1]

};

HSV rgbToHsv(int red, int green, int blue) {

if (red < 0 || red > 255 ||

green < 0 || green > 255 ||

blue < 0 || blue > 255) {

throw std::invalid_argument("Each RGB channel must be an integer from 0 to 255");

}

const double r = red / 255.0;

const double g = green / 255.0;

const double b = blue / 255.0;

const double maxChannel = std::max({r, g, b});

const double minChannel = std::min({r, g, b});

const double delta = maxChannel - minChannel;

const double value = maxChannel;

const double saturation = maxChannel == 0.0

? 0.0

: delta / maxChannel;

double hue = 0.0;

if (delta > 0.0) {

if (maxChannel == r) {

hue = 60.0 * ((g - b) / delta);

} else if (maxChannel == g) {

hue = 60.0 * ((b - r) / delta + 2.0);

} else {

hue = 60.0 * ((r - g) / delta + 4.0);

}

if (hue < 0.0) {

hue += 360.0;

}

}

return {hue, saturation, value};

}

int main() {

const HSV hsv = rgbToHsv(32, 128, 255);

std::cout << std::fixed << std::setprecision(2)

<< "H = " << hsv.h << " degrees\n"

<< "S = " << hsv.s * 100.0 << "%\n"

<< "V = " << hsv.v * 100.0 << "%\n";

return 0;

}

Using 255.0 is important because dividing two integer variables by the integer 255 would truncate each normalized channel. The delta check also handles achromatic colors without dividing by zero. Although the example program formats the result to two decimal places, the returned doubles remain unrounded.

Check the result with one calculation

Use RGB (32, 128, 255) as one end-to-end check. The normalized values are r = 32/255, g = 128/255, and b = 1. Therefore, the maximum is 1, the minimum is 32/255, and delta is 223/255. Substitution gives V = 1 and S = (223/255) / 1 = 0.8745098.

Because blue is the maximum channel, the hue formula is H = 240 + 60((r - g) / delta). Substituting the same values gives H = 240 + 60((32 - 128) / (255 - 32)) = 214.1704. The final display is therefore H = 214.17°, S = 87.45%, and V = 100.00%.

Match the scale expected by the destination

HSV coordinates are incomplete without their units. A mathematically correct result can still be rejected or misread when a library expects a compact integer range instead of degrees and fractions.

Destination convention Hue Saturation and value C++ handling
Mathematical or Android-style API Degrees, at least 0 and below 360 Fractions from 0 to 1 Return the struct values directly
Percentage-oriented interface Degrees Percentages from 0 to 100 Multiply fractions by 100 for display
Compact 8-bit image pipeline Follow the target documentation Follow the target documentation Apply the documented scaling after conversion

The Android Color.colorToHSV documentation defines hue in the nonnegative, below-360 degree range and saturation and value as zero-to-one values, matching the structure returned above.

OpenCV requires additional attention because its common 8-bit HSV output uses hue from 0 to 179 and saturation and value from 0 to 255, while image channels may be ordered BGR rather than RGB. Follow the dedicated OpenCV HSV scale guide before applying a packed conversion.

Handle achromatic colors without inventing hue

When red, green, and blue are equal, the color contains no visible hue: saturation is 0, and the hue coordinate has no visual meaning. The function leaves hue at the conventional placeholder of 0 degrees rather than dividing by the zero delta. Black also has saturation 0, but its value is 0 because all normalized channels are zero.

For a gray color, saturation remains 0 and value reflects the shared channel strength. The placeholder hue does not recover any earlier color information, so applications should not interpret it as a meaningful color-wheel position.

Verify the same triplet in your browser

For a no-code cross-check, the RGB to HSV Converter accepts the same 8-bit integer triplet and displays the converted coordinates alongside a live swatch.

  1. Enter whole-number red, green, and blue channel values from 0 through 255. Empty fields, decimal values, negative numbers, and values above 255 produce an explicit error instead of being silently rounded or clamped.
  2. Select Convert to HSV and read hue in degrees plus saturation and value as percentages. The page also shows the normalized HSV notation, source HEX code, and visual swatch.
  3. Check whether the destination expects degrees and percentages, zero-to-one fractions, or a compact integer range before copying the values.

The browser interface calculates locally, keeps the inputs visible for comparisons, and does not save a color history. It displays two decimal places for readability, while the underlying calculation retains unrounded floating-point values. Your C++ function should follow the same principle and leave final rounding to the output boundary.

Respect the boundaries of an RGB-to-HSV conversion

The coordinate transformation solves a numeric representation problem, not every color-management or design question:

  • HSV value is not HSL lightness. HSV value is the maximum normalized RGB channel, while HSL lightness uses the average of the maximum and minimum channels. Neither should be treated as measured perceptual luminance.
  • Alpha is outside the conversion. Transparency does not change the RGB-to-HSV calculation for the underlying three channels.
  • The input is an sRGB-style 8-bit triplet. The converter does not read embedded image profiles or convert between wide-gamut color spaces.
  • Destinations may round differently. Preserve full precision through the C++ calculation, then apply the scale and rounding rules documented by the receiving library.
  • Conversion does not establish readability. If the real goal is accessible foreground and background colors, test the actual pair with the Color Contrast Checker.