Estou procurando um conversor de espaço de cores de RGB para HSV, especificamente para a faixa de 0 a 255 para ambos os espaços de cores.
89
Eu usei isso por um longo tempo - não tenho ideia de onde eles vieram neste ponto ... Observe que as entradas e saídas, exceto para o ângulo em graus, estão na faixa de 0 a 1,0.
NOTA: este código não faz nenhuma verificação real de sanidade nas entradas. Prossiga com cuidado!
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;
}
>=
erro do compilador e é porquedouble == double
é inválido e ilegal na maioria dos compiladores. Aritmética de vírgula flutuante e armazenamento de vírgula flutuante significam que dois valores podem ser iguais em valor aproximado , mas não iguais em valor armazenado, embora formulaicamente sejam iguais. Você deve fazerabs(double_a - double_b) <= epsilon
onde épsilon tem algum valor, normalmente1e-4
.Você também pode tentar este código sem flutuações (mais rápido, mas menos preciso):
Observe que este algoritmo usa
0-255
como seu intervalo (não0-360
) conforme solicitado pelo autor desta pergunta.fonte
Escrevi isso em HLSL para nosso mecanismo de renderização, mas não há condições:
fonte
Aqui está uma implementação C baseada em Computação Gráfica e Modelagem Geométrica da Agoston : Implementação e Algoritmos p. 304, com H ∈ [0, 360] e S , V ∈ [0, 1].
fonte
isso deve estar aqui: funciona de qualquer maneira. E parece bom em comparação com os anteriores.
código hlsl
float3 é o tipo de dados vector3 de precisão de 16 bits, ou seja, float3 hue () retorna um tipo de dados (x, y, z) por exemplo (r, g, b), metade é o mesmo com metade da precisão, 8 bits, um float4 é (r, g, b, a) 4 valores.
fonte
half
,half4
,half3
,float3
, et cetera.A resposta de @finas tem um problema de estouro no Arduio conforme você diminui a saturação. Aqui está com alguns valores convertidos em int para evitar isso.
fonte
Este não é C, mas certamente funciona. Todos os outros métodos que vejo aqui funcionam encaixando tudo em partes de um hexágono e aproximando os "ângulos" disso. Em vez disso, ao começar com uma equação diferente usando cossenos e resolver para hs e v, você obtém um relacionamento muito melhor entre hsv e rgb, e a interpolação se torna mais suave (ao custo de ser muito mais lenta).
Suponha que tudo seja ponto flutuante. Se rg eb vão de 0 a 1, h vai de 0 a 2pi, v vai de 0 a 4/3 e s vai de 0 a 2/3.
O código a seguir foi escrito em Lua. É facilmente traduzível em qualquer outra coisa.
fonte
Versão GLSL Shader baseada na resposta de Patapoms:
fonte
Não sou desenvolvedor C ++, então não irei fornecer código. Mas posso fornecer um algoritmo simples de hsv2rgb (rgb2hsv aqui ) que descubro atualmente - atualizo o wiki com a descrição: HSV e HLS . A principal melhoria é que eu observo cuidadosamente r, g, b como funções de matiz e introduzo funções de forma mais simples para descrevê-las (sem perder a precisão). O Algoritmo - na entrada temos: h (0-255), s (0-255), v (0-255)
Usamos a função f descrita a seguir
onde (o mod pode retornar parte da fração; k é o número de ponto flutuante)
Aqui estão snippets / PoV em SO em JS: HSV e HSL
fonte
min(k,4-k,1)
. Por que existem três valores e o que exatamente está acontecendo aqui? Desde já, obrigado!Aqui está um conversor online com um artigo explicando todos os algoritmos para conversão de cores.
Você provavelmente preferiria uma versão C pronta, mas não deve demorar muito para ser aplicada e pode ajudar outras pessoas a tentarem fazer o mesmo em outra linguagem ou com outro espaço de cores.
fonte
Este link contém fórmulas para o que você deseja. Então é uma questão de desempenho (técnicas numéricas) se você quiser rápido.
fonte
Aqui está um que acabei de escrever esta manhã com base praticamente na mesma matemática acima:
fonte
Criei uma implementação possivelmente mais rápida usando a faixa 0-1 para RGBS e V e a faixa 0-6 para Hue (evitando a divisão) e agrupando os casos em duas categorias:
Para o intervalo de 0-255, apenas * 255.0f + 0,5f e atribua-o a um caractere sem sinal (ou divida por 255.0 para obter o oposto).
fonte
fonte