blind-spatial-mean.c (4867B)
1 /* See LICENSE file for copyright and license details. */ 2 #include "common.h" 3 4 USAGE("[-d | -g | -h | -l power-stream | -p power-stream | -v]") 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 *stream); 9 10 #define C (j & 3) 11 /* 12 * X-parameter 1: method enum value 13 * X-parameter 2: identifier-friendly name 14 * X-parameter 3: initial assignments 15 * X-parameter 4: initial value 16 * X-parameter 5: subcell processing 17 * X-parameter 6: subcell finalisation 18 */ 19 #define LIST_MEANS(TYPE)\ 20 /* [default] arithmetic mean */\ 21 X(ARITHMETIC, arithmetic,, 0, img[C] += *buf, img[C] /= pixels)\ 22 /* standard deviation */\ 23 X(STANDARD_DEVIATION, sd,, 0, (img[C] += *buf * *buf, aux[C] += *buf),\ 24 img[C] = nnpow((img[C] - aux[C] * aux[C] / pixels) / pixels, (TYPE)0.5)) \ 25 /* geometric mean */\ 26 X(GEOMETRIC, geometric,, 1, img[C] *= *buf, img[C] = nnpow(img[C], 1 / pixels))\ 27 /* harmonic mean */\ 28 X(HARMONIC, harmonic,, 0, img[C] += (TYPE)1 / *buf, img[C] = pixels / img[C])\ 29 /* Lehmer mean */\ 30 X(LEHMER, lehmer, (a[0] = powers[0] - (TYPE)1, a[1] = powers[1] - (TYPE)1,\ 31 a[2] = powers[2] - (TYPE)1, a[3] = powers[3] - (TYPE)1), 0,\ 32 (img[C] += nnpow(*buf, powers[C]), aux[C] += nnpow(*buf, a[C])), img[C] /= aux[C])\ 33 /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\ 34 X(POWER, power,, 0, img[C] += nnpow(*buf, powers[C]),\ 35 img[C] = nnpow(img[C], (TYPE)1 / powers[C]) / pixels)\ 36 /* variance */\ 37 X(VARIANCE, variance,, 0, (img[C] += *buf * *buf, aux[C] += *buf),\ 38 img[C] = (img[C] - aux[C] * aux[C] / pixels) / pixels) 39 40 #define X(V, ...) V, 41 enum method { LIST_MEANS() }; 42 #undef X 43 44 static struct stream power; 45 static const char *power_file = NULL; 46 47 #define MAKE_PROCESS(PIXFMT, TYPE,\ 48 _1, NAME, INIT, INITIAL, PROCESS_SUBCELL, FINALISE_SUBCELL)\ 49 static void\ 50 process_##PIXFMT##_##NAME(struct stream *stream)\ 51 {\ 52 TYPE img[4], aux[4], *buf, a[4], powers[4];\ 53 TYPE pixels = (TYPE)(stream->frame_size / sizeof(img));\ 54 size_t i, n, j = 0, m = stream->frame_size / sizeof(*img);\ 55 int first = 1;\ 56 do {\ 57 n = stream->ptr / stream->pixel_size * stream->n_chan;\ 58 buf = (TYPE *)(stream->buf);\ 59 for (i = 0; i < n; i++, buf++, j++, j %= m) {\ 60 if (!j) {\ 61 if (!first) {\ 62 for (j = 0; j < ELEMENTSOF(img); j++)\ 63 FINALISE_SUBCELL;\ 64 j = 0;\ 65 ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\ 66 }\ 67 first = 0;\ 68 if (power_file && !eread_frame(&power, powers))\ 69 return;\ 70 INIT;\ 71 img[0] = aux[0] = INITIAL;\ 72 img[1] = aux[1] = INITIAL;\ 73 img[2] = aux[2] = INITIAL;\ 74 img[3] = aux[3] = INITIAL;\ 75 }\ 76 PROCESS_SUBCELL;\ 77 }\ 78 n *= sizeof(TYPE);\ 79 memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ 80 } while (eread_stream(stream, SIZE_MAX));\ 81 if (!first) {\ 82 for (j = 0; j < ELEMENTSOF(img); j++)\ 83 FINALISE_SUBCELL;\ 84 ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\ 85 }\ 86 (void) aux, (void) a, (void) powers, (void) pixels;\ 87 } 88 #define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__) 89 LIST_MEANS(double) 90 #undef X 91 #define X(...) MAKE_PROCESS(f, float, __VA_ARGS__) 92 LIST_MEANS(float) 93 #undef X 94 #undef MAKE_PROCESS 95 #undef C 96 97 #define X(ID, NAME, ...) [ID] = process_lf_##NAME, 98 static const process_func process_functions_lf[] = { LIST_MEANS() }; 99 #undef X 100 101 #define X(ID, NAME, ...) [ID] = process_f_##NAME, 102 static const process_func process_functions_f[] = { LIST_MEANS() }; 103 #undef X 104 105 int 106 main(int argc, char *argv[]) 107 { 108 struct stream stream; 109 process_func process; 110 enum method method = ARITHMETIC; 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 'l': 123 method = LEHMER; 124 power_file = UARGF(); 125 break; 126 case 'p': 127 method = POWER; 128 power_file = UARGF(); 129 break; 130 case 'v': 131 method = VARIANCE; 132 break; 133 default: 134 usage(); 135 } ARGEND; 136 137 if (argc) 138 usage(); 139 140 eopen_stream(&stream, NULL); 141 if (power_file != NULL) { 142 eopen_stream(&power, power_file); 143 if (power.width != 1 || power.height != 1) 144 eprintf("%s: videos do not have the 1x1 geometry\n", power_file); 145 if (strcmp(power.pixfmt, stream.pixfmt)) 146 eprintf("videos use incompatible pixel formats\n"); 147 } 148 149 CHECK_N_CHAN(&stream, 4, 4); 150 if (stream.encoding == DOUBLE) 151 process = process_functions_lf[method]; 152 else if (stream.encoding == FLOAT) 153 process = process_functions_f[method]; 154 else 155 eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); 156 157 if (DPRINTF_HEAD(STDOUT_FILENO, stream.frames, 1, 1, stream.pixfmt) < 0) 158 eprintf("dprintf:"); 159 process(&stream); 160 if (stream.ptr) 161 eprintf("%s: incomplete frame\n", stream.file); 162 return 0; 163 }