Ich suche einen Farbraumkonverter von RGB zu HSV, speziell für den Bereich 0 bis 255 für beide Farbräume.
89
Ich habe diese für eine lange Zeit verwendet - keine Ahnung, woher sie zu diesem Zeitpunkt kamen ... Beachten Sie, dass die Ein- und Ausgänge mit Ausnahme des Winkels in Grad im Bereich von 0 bis 1,0 liegen.
HINWEIS: Dieser Code führt keine echte Überprüfung der Integrität von Eingaben durch. Mit Vorsicht fortfahren!
typedef struct {
double r; // a fraction between 0 and 1
double g; // a fraction between 0 and 1
double b; // a fraction between 0 and 1
} rgb;
typedef struct {
double h; // angle in degrees
double s; // a fraction between 0 and 1
double v; // a fraction between 0 and 1
} hsv;
static hsv rgb2hsv(rgb in);
static rgb hsv2rgb(hsv in);
hsv rgb2hsv(rgb in)
{
hsv out;
double min, max, delta;
min = in.r < in.g ? in.r : in.g;
min = min < in.b ? min : in.b;
max = in.r > in.g ? in.r : in.g;
max = max > in.b ? max : in.b;
out.v = max; // v
delta = max - min;
if (delta < 0.00001)
{
out.s = 0;
out.h = 0; // undefined, maybe nan?
return out;
}
if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash
out.s = (delta / max); // s
} else {
// if max is 0, then r = g = b = 0
// s = 0, h is undefined
out.s = 0.0;
out.h = NAN; // its now undefined
return out;
}
if( in.r >= max ) // > is bogus, just keeps compilor happy
out.h = ( in.g - in.b ) / delta; // between yellow & magenta
else
if( in.g >= max )
out.h = 2.0 + ( in.b - in.r ) / delta; // between cyan & yellow
else
out.h = 4.0 + ( in.r - in.g ) / delta; // between magenta & cyan
out.h *= 60.0; // degrees
if( out.h < 0.0 )
out.h += 360.0;
return out;
}
rgb hsv2rgb(hsv in)
{
double hh, p, q, t, ff;
long i;
rgb out;
if(in.s <= 0.0) { // < is bogus, just shuts up warnings
out.r = in.v;
out.g = in.v;
out.b = in.v;
return out;
}
hh = in.h;
if(hh >= 360.0) hh = 0.0;
hh /= 60.0;
i = (long)hh;
ff = hh - i;
p = in.v * (1.0 - in.s);
q = in.v * (1.0 - (in.s * ff));
t = in.v * (1.0 - (in.s * (1.0 - ff)));
switch(i) {
case 0:
out.r = in.v;
out.g = t;
out.b = p;
break;
case 1:
out.r = q;
out.g = in.v;
out.b = p;
break;
case 2:
out.r = p;
out.g = in.v;
out.b = t;
break;
case 3:
out.r = p;
out.g = q;
out.b = in.v;
break;
case 4:
out.r = t;
out.g = p;
out.b = in.v;
break;
case 5:
default:
out.r = in.v;
out.g = p;
out.b = q;
break;
}
return out;
}
>=
Fehler und den Compilerfehler ist, dass erdouble == double
in den meisten Compilern ungültig und unzulässig ist. Gleitkomma-Arithmetik und Gleitkomma-Speicherung bedeuten, dass zwei Werte im ungefähren Wert gleich sein können, aber im gespeicherten Wert nicht gleich sind, obwohl sie formelmäßig gleich sind. Sie sollten tun,abs(double_a - double_b) <= epsilon
wo epsilon normalerweise einen Wert hat1e-4
.Sie können diesen Code auch ohne Floats ausprobieren (schneller, aber weniger genau):
Beachten Sie, dass dieser Algorithmus
0-255
als Bereich (nicht0-360
) verwendet, wie dies vom Autor dieser Frage angefordert wurde.quelle
Ich habe dies in HLSL für unsere Rendering-Engine geschrieben, es enthält keine Bedingungen:
quelle
Hier ist eine C-Implementierung, die auf Agostons Computergrafik und geometrischer Modellierung basiert : Implementierung und Algorithmen p. 304 mit H ∈ [0, 360] und S , V ∈ [0, 1].
quelle
das sollte hier sein: es funktioniert trotzdem. Und es sieht gut aus im Vergleich zu den oben genannten.
hlsl code
float3 ist ein Vektortyp mit 16 Bit Genauigkeit vektor3, dh float3 hue () gibt einen Datentyp (x, y, z) zurück, z. B. (r, g, b), die Hälfte ist mit halber Genauigkeit gleich, 8 Bit, ein float4 ist (r, g, b, a) 4 Werte.
quelle
half
,half4
,half3
,float3
, et cetera.Die Antwort von @ fins hat ein Überlaufproblem bei Arduio, wenn Sie die Sättigung verringern. Hier werden einige Werte in int konvertiert, um dies zu verhindern.
quelle
Dies ist nicht C, aber es funktioniert auf jeden Fall. Alle anderen Methoden, die ich hier sehe, funktionieren, indem alles in Teile eines Sechsecks gehüllt und daraus "Winkel" angenähert werden. Wenn Sie stattdessen mit einer anderen Gleichung unter Verwendung von Kosinus beginnen und nach hs und v auflösen, erhalten Sie eine viel schönere Beziehung zwischen hsv und rgb, und das Tweening wird reibungsloser (auf Kosten einer viel langsameren).
Angenommen, alles ist Gleitkomma. Wenn rg und b von 0 auf 1 gehen, geht h von 0 auf 2 pi, v geht von 0 auf 4/3 und s geht von 0 auf 2/3.
Der folgende Code ist in Lua geschrieben. Es ist leicht in etwas anderes übersetzbar.
quelle
GLSL Shader Version basierend auf Patapoms Antwort:
quelle
Ich bin kein C ++ - Entwickler, daher werde ich keinen Code bereitstellen. Aber ich kann einen einfachen hsv2rgb- Algorithmus (rgb2hsv hier ) bereitstellen , den ich derzeit entdecke - ich aktualisiere das Wiki mit der Beschreibung: HSV und HLS . Die Hauptverbesserung besteht darin, dass ich r, g, b sorgfältig als Farbtonfunktionen beobachte und eine einfachere Formfunktion einführe, um sie zu beschreiben (ohne an Genauigkeit zu verlieren). Der Algorithmus - bei Eingabe haben wir: h (0-255), s (0-255), v (0-255)
Wir verwenden die wie folgt beschriebene Funktion f
wobei (mod kann Bruchteil zurückgeben; k ist Gleitkommazahl)
Hier sind Snippets / PoV in SO in JS: HSV und HSL
quelle
min(k,4-k,1)
. Warum gibt es drei Werte und was passiert hier genau? Danke im Voraus!Hier ist ein Online-Konverter mit einem Artikel, nachdem alle Algorithmen für die Farbkonvertierung erläutert wurden.
Sie würden wahrscheinlich eine fertige C-Version bevorzugen, aber die Anwendung sollte nicht lange dauern und könnte anderen Personen helfen, die versuchen, dasselbe in einer anderen Sprache oder mit einem anderen Farbraum zu tun.
quelle
Dieser Link enthält Formeln für das, was Sie möchten. Dann ist es eine Frage der Leistung (numerische Techniken), wenn Sie es schnell wollen.
quelle
Hier ist eine, die ich heute Morgen geschrieben habe, basierend auf fast der gleichen Mathematik wie oben:
quelle
Ich habe eine möglicherweise schnellere Implementierung erstellt, indem ich den Bereich 0-1 für RGBS und V und den Bereich 0-6 für Hue verwendet habe (Vermeidung der Unterteilung) und die Fälle in zwei Kategorien eingeteilt habe:
Für den Bereich 0-255 nur * 255.0f + 0.5f und weisen Sie ihn einem vorzeichenlosen Zeichen zu (oder dividieren Sie durch 255.0, um das Gegenteil zu erhalten).
quelle
quelle