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 }