Added test for rgb->hsv->rgb, and fixed function
parent
01285dc197
commit
8a30340202
@ -0,0 +1,9 @@
|
||||
#ifndef HSV_H
|
||||
#define HSV_H
|
||||
|
||||
#include "cglm/types.h"
|
||||
|
||||
void hsv_to_rgb(double hsv[3], vec3 rgb);
|
||||
void rgb_to_hsv(vec3 rgb, double hsv[3]);
|
||||
|
||||
#endif
|
@ -0,0 +1,75 @@
|
||||
#include "hsv.h"
|
||||
#include "math.h"
|
||||
|
||||
#define max(a, b) ((a > b) ? a : b)
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
|
||||
float floatmod(float a, float b) {
|
||||
return a - b*floor(a/b);
|
||||
}
|
||||
|
||||
void rgb_to_hsv(vec3 rgb, double hsv[3]) {
|
||||
if(rgb[0] == 0 && rgb[1] == 0 && rgb[2] == 0) {
|
||||
hsv[0] = 0;
|
||||
hsv[1] = 0;
|
||||
hsv[2] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
hsv[2] = max(rgb[0], max(rgb[1], rgb[2]));
|
||||
float M = min(rgb[0], min(rgb[1], rgb[2]));
|
||||
float C = hsv[2] - M;
|
||||
hsv[1] = C / hsv[2];
|
||||
float X;
|
||||
|
||||
if(hsv[2] == rgb[0] && M == rgb[2]) {
|
||||
X = rgb[1] - M;
|
||||
hsv[0] = (X/C + 0)/6;
|
||||
} else if(hsv[2] == rgb[1] && M == rgb[2]) {
|
||||
X = rgb[0] - M;
|
||||
hsv[0] = (2 - X/C)/6;
|
||||
} else if(hsv[2] == rgb[1] && M == rgb[0]) {
|
||||
X = rgb[2] - M;
|
||||
hsv[0] = (X/C + 2)/6;
|
||||
} else if(hsv[2] == rgb[2] && M == rgb[0]) {
|
||||
X = rgb[1] - M;
|
||||
hsv[0] = (4 - X/C)/6;
|
||||
} else if(hsv[2] == rgb[2] && M == rgb[1]) {
|
||||
X = rgb[0] - M;
|
||||
hsv[0] = (X/C + 4)/6;
|
||||
} else if(hsv[2] == rgb[0] && M == rgb[1]) {
|
||||
X = rgb[2] - M;
|
||||
hsv[0] = (6 - X/C)/6;
|
||||
}
|
||||
}
|
||||
|
||||
void hsv_to_rgb(double hsv[3], vec3 rgb) {
|
||||
float C = hsv[1] * hsv[2];
|
||||
float H = hsv[0]*6;
|
||||
float X = C * (1 - fabs(floatmod(H, 2) - 1));
|
||||
vec4 temp = {0, 0, 0, 0};
|
||||
if(0 <= H && H <= 1) {
|
||||
temp[0] = C;
|
||||
temp[1] = X;
|
||||
} else if(1 <= H && H <= 2) {
|
||||
temp[0] = X;
|
||||
temp[1] = C;
|
||||
} else if(2 <= H && H <= 3) {
|
||||
temp[1] = C;
|
||||
temp[2] = X;
|
||||
} else if(3 <= H && H <= 4) {
|
||||
temp[1] = X;
|
||||
temp[2] = C;
|
||||
} else if(4 <= H && H <= 5) {
|
||||
temp[0] = X;
|
||||
temp[2] = C;
|
||||
} else if(5 <= H && H <= 6) {
|
||||
temp[0] = C;
|
||||
temp[2] = X;
|
||||
}
|
||||
|
||||
float m = hsv[2] - C;
|
||||
rgb[0] = temp[0] + m;
|
||||
rgb[1] = temp[1] + m;
|
||||
rgb[2] = temp[2] + m;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
#include "hsv.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define FAIL -1
|
||||
#define OK 0
|
||||
|
||||
int test_conv(int r, int g, int b, double tolerance) {
|
||||
vec3 rgb = {r/255.0, g/255.0, b/255.0};
|
||||
double hsv[3];
|
||||
vec3 out;
|
||||
int test[3];
|
||||
rgb_to_hsv(rgb, hsv);
|
||||
hsv_to_rgb(hsv, out);
|
||||
test[0] = out[0]*255.0;
|
||||
test[1] = out[1]*255.0;
|
||||
test[2] = out[2]*255.0;
|
||||
|
||||
if(fabs(rgb[0] - out[0]) > tolerance || fabs(rgb[1] - out[1]) > tolerance || fabs(rgb[2] - out[2]) > tolerance) {
|
||||
fprintf(stderr, "FAIL:\t#%02X%02X%02X -> #%02X%02X%02X\nIN:\t(%.12f %.12f %.12f)\nOUT:\t(%.12f %.12f %.12f)\nDIF:\t(%.12f %.12f %.12f)\n",
|
||||
r, g, b,
|
||||
test[0], test[1], test[2],
|
||||
rgb[0], rgb[1], rgb[2],
|
||||
out[0], out[1], out[2],
|
||||
rgb[0]-out[0], rgb[1]-out[1], rgb[2]-out[2]);
|
||||
return FAIL;
|
||||
} else {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
for(int r = 0; r < 256; r++) {
|
||||
for(int g = 0; g < 256; g++) {
|
||||
for(int b = 0; b < 256; b++) {
|
||||
if(test_conv(r, g, b, 0.001) != OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To RGB steps:
|
||||
// 1. C = V * S <- maps to 3 in inv
|
||||
// 2. H' = H * 6 <- maps to 7 in inv
|
||||
// 3. X = C * (1 - abs(H' - 2*floor(H'/2) - 1))
|
||||
// 4. M = V - C <- maps to 4 in inv
|
||||
// 5. R = V, G = X + M, B = M
|
||||
|
||||
// To HSV steps:
|
||||
// 1. V = max(R, G, B) <- maps to 5,R in inv
|
||||
// 2. M = min(R, G, B) <- maps to 5,B in inv
|
||||
// 3. S = C / V <- maps to 1 in inv
|
||||
// 4. C = V - M <- maps to 4 in inv
|
||||
// 5. X = G - M
|
||||
// 6. H' = X/C
|
||||
// 7. H = H'/6 <- maps to 2 in inv
|
||||
//
|
||||
// So out of the two algos, the only step that doest match exactly so far is
|
||||
// RGB: X = C * (1 - abs(H' - 2*floor(H'/2) - 1))
|
||||
// HSV: X = G - M, H' = X/C
|
||||
//
|
||||
// After floor():
|
||||
// RGB: X = C * (1 - abs(H' - 1))
|
||||
//
|
||||
// After abs() assuming H' = [0, 1]:
|
||||
// RGB: X = C * (1 - (1 - H'))
|
||||
// RGB: X = C * H'
|
Loading…
Reference in New Issue