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