empirical tweaks to emc algorithm
[stereofy] / anaglyph.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int error(int code);
6 int mm(int v, int min, int max);
7 int anaglyph(FILE *in1, FILE *in2, FILE *out,
8         unsigned char* (*alg)(unsigned char*, const unsigned char*, const unsigned char*) );
9 unsigned char* (*parse_func(const char *arg))(unsigned char*, const unsigned char*, const unsigned char*);
10
11 unsigned char* full_gm(unsigned char *out, const unsigned char *l, const unsigned char *r);
12 unsigned char* half_gm(unsigned char *out, const unsigned char *l, const unsigned char *r);
13 unsigned char* dubois_gm(unsigned char *out, const unsigned char *l, const unsigned char *r);
14 unsigned char* full_rc(unsigned char *out, const unsigned char *l, const unsigned char *r);
15 unsigned char* half_rc(unsigned char *out, const unsigned char *l, const unsigned char *r);
16 unsigned char* dubois_rc(unsigned char *out, const unsigned char *l, const unsigned char *r);
17 unsigned char* full_mc(unsigned char *out, const unsigned char *l, const unsigned char *r);
18 unsigned char* dubois_mc(unsigned char *out, const unsigned char *l, const unsigned char *r);
19 unsigned char* dubois_ab(unsigned char *out, const unsigned char *l, const unsigned char *r);
20
21 int main(int argc, char *argv[]){
22   FILE *in1, *in2, *out; int cnt; in1 = in2 = out = NULL;
23   unsigned char* (*alg)(unsigned char[], const unsigned char[], const unsigned char[]) = &dubois_rc;
24
25   if (argc < 4 || argc > 5) return error(1);
26   for (cnt = 1; cnt < argc; cnt++) {
27     if (argv[cnt][0] == '-') alg = parse_func(argv[cnt]);
28     else if (!in1){ if ((in1 = fopen(argv[cnt], "r")) == NULL) return error(2);}
29     else if (!in2){ if ((in2 = fopen(argv[cnt], "r")) == NULL) return error(2);}
30     else if (!out){ if ((out = fopen(argv[cnt], "w")) == NULL) return error(3);}
31   }
32   return anaglyph(in1, in2, out, alg);
33 }
34
35 int error(int code){
36   char *msg = "Unknown Error\n";
37   switch (code) {
38     case 1: msg = "Usage: anaglyph [ -[fhd]gm | -[fhd]rc | -fmc | -dab ] left.rgb right.rgb output.rgb\n";
39     case 2: msg = "Could not open input file for reading\n";
40     case 3: msg = "Could not open output file for writing\n";
41     case 4: msg = "Unexpected end of file\n";
42     case 5: msg = "Cannot write to output file\n";
43   }
44   fprintf(stderr, msg); return code;
45 }
46
47 // min-max to prevent overflowing in Dubois calculations
48 int mm(int v, int min, int max){
49   if (v < min) return min;
50   else if (v > max) return max;
51   else return v;
52 }
53
54 //green-magenta full-color
55 unsigned char* full_gm(unsigned char *out, const unsigned char *l, const unsigned char *r){
56   out[0] = r[0];
57   out[1] = l[1];
58   out[2] = r[2];
59   return out;
60 }
61
62 //green-magenta half-color
63 unsigned char* half_gm(unsigned char *out, const unsigned char *l, const unsigned char *r){
64   out[0] = r[0];
65   //green channel is derived from chroma value of left image
66   out[1] = (unsigned char)(int)((299*(int)l[0] + 587*(int)l[1] + 114*(int)l[2]) / 1000);
67   out[2] = r[2];
68
69   return out;
70 }
71
72 //green-magenta Dubois
73 unsigned char* dubois_gm(unsigned char *out, const unsigned char *l, const unsigned char *r){
74   out[0] = (unsigned char)mm((-62*(int)l[0] + -158*(int)l[1] + -39*(int)l[2] +
75         529*(int)r[0] + 705*(int)r[1] +   24*(int)r[2]) / 1000, 0, 255);
76   out[1] = (unsigned char)mm((284*(int)l[0] +  668*(int)l[1] + 143*(int)l[2] +
77         -16*(int)r[0] + -15*(int)r[1] +  -65*(int)r[2]) / 1000, 0, 255);
78   out[2] = (unsigned char)mm((-15*(int)l[0] +  -27*(int)l[1] +  21*(int)l[2] +
79           9*(int)r[0] +  75*(int)r[1] +  937*(int)r[2]) / 1000, 0, 255);
80   return out;
81 }
82
83 //red-cyan full-color
84 unsigned char* full_rc(unsigned char *out, const unsigned char *l, const unsigned char *r){
85   out[0] = l[0];
86   out[1] = r[1];
87   out[2] = r[2];
88   return out;
89 }
90
91 //red-cyan half-color
92 unsigned char* half_rc(unsigned char *out, const unsigned char *l, const unsigned char *r){
93   //red channel is derived from chroma value of left image
94   out[0] = (unsigned char)(int)((299*(int)l[0] + 587*(int)l[1] + 114*(int)l[2]) / 1000);
95   out[1] = r[1];
96   out[2] = r[2];
97
98   return out;
99 }
100
101 //red-cyan Dubois
102 unsigned char* dubois_rc(unsigned char *out, const unsigned char *l, const unsigned char *r){
103   out[0] = (unsigned char) mm((456*(int)l[0] +  500*(int)l[1] + 176*(int)l[2] +
104         -43*(int)r[0] + -88*(int)r[1] +   -2*(int)r[2]) / 1000, 0, 255);
105   out[1] = (unsigned char) mm((-40*(int)l[0] +  -38*(int)l[1] + -16*(int)l[2] +
106         378*(int)r[0] + 734*(int)r[1] +  -18*(int)r[2]) / 1000, 0, 255);
107   out[2] = (unsigned char) mm((-15*(int)l[0] +  -21*(int)l[1] +  -5*(int)l[2] +
108         -72*(int)r[0] +-113*(int)r[1] + 1226*(int)r[2]) / 1000, 0, 255);
109   return out;
110 }
111
112 //magenta-cyan full-color
113 unsigned char* full_mc(unsigned char *out, const unsigned char *l, const unsigned char *r){
114   out[0] = l[0];
115   out[1] = r[1];
116   out[2] = (unsigned char)(((int)r[2] + (int)l[2]) / 2);
117   return out;
118 }
119
120 //magenta-cyan experimental
121 unsigned char* experimental_mc(unsigned char *out, const unsigned char *l, const unsigned char *r){
122   out[0] = (unsigned char) mm((556*(int)l[0] +  400*(int)l[1] + 176*(int)l[2] +
123         -43*(int)r[0] + -88*(int)r[1] +   -2*(int)r[2]) / 950, 0, 255);
124   out[1] = (unsigned char) mm((-40*(int)l[0] +  -38*(int)l[1] + -16*(int)l[2] +
125         278*(int)r[0] + 734*(int)r[1] +  -18*(int)r[2]) / 1100, 0, 255);
126   out[2] = (unsigned char) mm((-15*(int)l[0] +  -21*(int)l[1] + 600*(int)l[2] +
127         -72*(int)r[0] +-113*(int)r[1] + 621*(int)r[2]) / 950, 0, 255);
128   return out;
129 }
130
131 //amber-blue Dubois
132 unsigned char* dubois_ab(unsigned char *out, const unsigned char *l, const unsigned char *r){
133   out[0] = (unsigned char)mm((1062*(int)l[0] + -205*(int)l[1] +299*(int)l[2] +
134         -16*(int)r[0] +-123*(int)r[1] +  -17*(int)r[2]) / 1000, 0, 255);
135   out[1] = (unsigned char)mm((-26*(int)l[0] +  908*(int)l[1] +  68*(int)l[2] +
136           6*(int)r[0] +  62*(int)r[1] +  -17*(int)r[2]) / 1000, 0, 255);
137   out[2] = (unsigned char)mm((-38*(int)l[0] + -173*(int)l[1] +  22*(int)l[2] +
138          94*(int)r[0] + 185*(int)r[1] +  911*(int)r[2]) / 1000, 0, 255);
139   return out;
140 }
141
142 unsigned char* (*parse_func(const char *arg))(unsigned char*, const unsigned char*, const unsigned char*){
143   if (!strcmp(arg, "-fgm")) return &full_gm;
144   if (!strcmp(arg, "-hgm")) return &half_gm;
145   if (!strcmp(arg, "-dgm")) return &dubois_gm;
146
147   if (!strcmp(arg, "-frc")) return &full_rc;
148   if (!strcmp(arg, "-hrc")) return &half_rc;
149   if (!strcmp(arg, "-drc")) return &dubois_rc;
150
151   if (!strcmp(arg, "-fmc")) return &full_mc;
152   if (!strcmp(arg, "-dab")) return &dubois_ab;
153   if (!strcmp(arg, "-emc")) return &experimental_mc;
154   exit(error(1)); return &dubois_rc;
155 }
156
157 int anaglyph(FILE *in1, FILE *in2, FILE *out,
158         unsigned char* (*alg)(unsigned char*, const unsigned char*, const unsigned char*) ){
159   unsigned char *i1 = malloc(3), *i2 = malloc(3), *o = malloc(3);
160
161   while (fread( i1, 1, 3, in1) && fread( i2, 1, 3, in2)){
162     if (!fwrite(alg( o, i1, i2), 1, 3, out)) return error(5);
163   }
164   return 0;
165 }