blind-mean.c - blind - suckless command-line video editing utility
(HTM) git clone git://git.suckless.org/blind
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
blind-mean.c (5615B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-d | -g | -h | -H | -i | -l power-stream | -L | -p power-stream | -s power-stream | -v | -z power] stream-1 stream-2 ...")
5 /* TODO add [-w weight-stream] for [-ghlpv] */
6
7 /* Because the syntax for a function returning a function pointer is disgusting. */
8 typedef void (*process_func)(struct stream *streams, size_t n_streams, size_t n);
9
10 /*
11 * X-parameter 1: method enum value
12 * X-parameter 2: identifier-friendly name
13 * X-parameter 3: initial assignments
14 * X-parameter 4: initial value
15 * X-parameter 5: subcell processing
16 * X-parameter 6: subcell finalisation
17 */
18 #define LIST_MEANS(TYPE)\
19 /* [default] arithmetic mean */\
20 X(ARITHMETIC, arithmetic, sn = (TYPE)1 / sn, 0, img += val, img *= sn) \
21 /* standard deviation */\
22 X(STANDARD_DEVIATION, sd, sn = (TYPE)1 / sn, 0, (img += val * val, aux += val),\
23 img = nnpow((img - aux * aux * sn) * sn, (TYPE)0.5))\
24 /* geometric mean */\
25 X(GEOMETRIC, geometric, sn = (TYPE)1 / sn, 1, img *= val, img = nnpow(img, sn))\
26 /* harmonic mean */\
27 X(HARMONIC, harmonic,, 0, img += (TYPE)1 / val, img = sn / img)\
28 /* Heronian mean */\
29 X(HERONIAN, heronian,, 0, auxs[j] = val,\
30 img = (auxs[0] + sqrt(auxs[0] * auxs[1]) + auxs[1]) / (TYPE)3)\
31 /* identric mean */\
32 X(IDENTRIC, identric, a = (TYPE)(1. / M_E), 0, auxs[j] = val,\
33 img = auxs[0] == auxs[1] ? auxs[0] :\
34 nnpow(nnpow(auxs[0], auxs[0]) / nnpow(auxs[1], auxs[1]), auxs[0] - auxs[1]) * a)\
35 /* Lehmer mean */\
36 X(LEHMER, lehmer,, 0, (img += nnpow(val, *pows), aux += nnpow(val, *pows - (TYPE)1)), img /= aux)\
37 /* logarithmic mean */\
38 X(LOGARITHMIC, logarithmic,, 0, auxs[j] = val,\
39 img = auxs[0] == auxs[1] ? auxs[0] : (!auxs[0] || !auxs[1]) ? (TYPE)0 :\
40 (auxs[1] - auxs[0]) / log(auxs[1] / auxs[0]))\
41 /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\
42 X(POWER, power, sn = (TYPE)1 / sn, 0,\
43 img += nnpow(val, *pows), img = nnpow(img, (TYPE)1 / *pows) * sn)\
44 /* Stolarsky mean */\
45 X(STOLARSKY, stolarsky,, 0, auxs[j] = val,\
46 img = auxs[0] == auxs[1] ? auxs[0] :\
47 nnpow((nnpow(auxs[0], *pows) - nnpow(auxs[1], *pows)) /\
48 (*pows * (auxs[0] - auxs[1])), (TYPE)1 / (*pows - (TYPE)1)))\
49 /* variance */\
50 X(VARIANCE, variance, sn = (TYPE)1 / sn, 0, (img += val * val, aux += val),\
51 img = (img - aux * aux * sn) * sn)\
52 /* Heinz mean */\
53 X(HEINZ, heinz,, 0, auxs[j] = val,\
54 img = (nnpow(auxs[0], *pows) * nnpow(auxs[1], (TYPE)1 - *pows) +\
55 nnpow(auxs[0], (TYPE)1 - *pows) * nnpow(auxs[1], *pows)) / (TYPE)2)
56
57 #define X(V, ...) V,
58 enum method { LIST_MEANS() };
59 #undef X
60
61 static const char *power_file = NULL;
62
63 #define aux (*auxs)
64 #define MAKE_PROCESS(PIXFMT, TYPE,\
65 _1, NAME, INIT, INITIAL, PROCESS_SUBCELL, FINALISE_SUBCELL)\
66 static void\
67 process_##PIXFMT##_##NAME(struct stream *streams, size_t n_streams, size_t n)\
68 {\
69 size_t i, j;\
70 TYPE img, auxs[2], val, a, sn;\
71 TYPE *pows = power_file ? (TYPE *)(streams[n_streams - 1].buf) : NULL;\
72 n_streams -= (size_t)!!power_file;\
73 sn = (TYPE)n_streams;\
74 INIT;\
75 for (i = 0; i < n; i += sizeof(TYPE), pows++) {\
76 img = auxs[0] = auxs[1] = INITIAL;\
77 for (j = 0; j < n_streams; j++) {\
78 val = *(TYPE *)(streams[j].buf + i);\
79 PROCESS_SUBCELL;\
80 }\
81 FINALISE_SUBCELL;\
82 *(TYPE *)(streams->buf + i) = img;\
83 }\
84 (void) aux, (void) a, (void) pows, (void) sn;\
85 }
86 #define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__)
87 LIST_MEANS(double)
88 #undef X
89 #define X(...) MAKE_PROCESS(f, float, __VA_ARGS__)
90 LIST_MEANS(float)
91 #undef X
92 #undef MAKE_PROCESS
93 #undef aux
94
95 #define X(ID, NAME, ...) [ID] = process_lf_##NAME,
96 static const process_func process_functions_lf[] = { LIST_MEANS() };
97 #undef X
98
99 #define X(ID, NAME, ...) [ID] = process_f_##NAME,
100 static const process_func process_functions_f[] = { LIST_MEANS() };
101 #undef X
102
103 int
104 main(int argc, char *argv[])
105 {
106 struct stream *streams;
107 process_func process;
108 size_t frames = SIZE_MAX, tmp;
109 enum method method = ARITHMETIC;
110 int i, two = 0;
111
112 ARGBEGIN {
113 case 'd':
114 method = STANDARD_DEVIATION;
115 break;
116 case 'g':
117 method = GEOMETRIC;
118 break;
119 case 'h':
120 method = HARMONIC;
121 break;
122 case 'H':
123 method = HERONIAN;
124 two = 1;
125 break;
126 case 'i':
127 method = IDENTRIC;
128 two = 1;
129 break;
130 case 'l':
131 method = LEHMER;
132 power_file = UARGF();
133 break;
134 case 'L':
135 method = LOGARITHMIC;
136 two = 1;
137 break;
138 case 'p':
139 method = POWER;
140 power_file = UARGF();
141 break;
142 case 's':
143 method = STOLARSKY;
144 two = 1;
145 power_file = UARGF();
146 break;
147 case 'v':
148 method = VARIANCE;
149 break;
150 case 'z':
151 method = HEINZ;
152 two = 1;
153 power_file = UARGF();
154 break;
155 default:
156 usage();
157 } ARGEND;
158
159 if (argc < 2 || (argc > 2 && two))
160 usage();
161
162 streams = alloca((size_t)(argc + !!power_file) * sizeof(*streams));
163 for (i = 0; i < argc; i++) {
164 eopen_stream(streams + i, argv[i]);
165 if (streams[i].frames && streams[i].frames < frames)
166 frames = streams[i].frames;
167 }
168 if (power_file != NULL)
169 eopen_stream(streams + argc, power_file);
170
171 if (streams->encoding == DOUBLE)
172 process = process_functions_lf[method];
173 else if (streams->encoding == FLOAT)
174 process = process_functions_f[method];
175 else
176 eprintf("pixel format %s is not supported, try xyza\n", streams->pixfmt);
177
178 tmp = streams->frames, streams->frames = frames;
179 fprint_stream_head(stdout, streams);
180 efflush(stdout, "<stdout>");
181 streams->frames = tmp;
182 process_multiple_streams(streams, (size_t)(argc + !!power_file),
183 STDOUT_FILENO, "<stdout>", 1, process);
184 return 0;
185 }