| blind-spatial-mean.c - blind - suckless command-line video editing utility | |
| git clone git://git.suckless.org/blind | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| 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 dis… | |
| 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] += … | |
| 24 img[C] = nnpow((img[C] - aux[C] * aux[C] / pixels) / pixels, (… | |
| 25 /* geometric mean */\ | |
| 26 X(GEOMETRIC, geometric,, 1, img[C] *= *buf, img[C] = nnpow(img[C… | |
| 27 /* harmonic mean */\ | |
| 28 X(HARMONIC, harmonic,, 0, img[C] += (TYPE)1 / *buf, img[C] = pix… | |
| 29 /* Lehmer mean */\ | |
| 30 X(LEHMER, lehmer, (a[0] = powers[0] - (TYPE)1, a[1] = powers[1] … | |
| 31 a[2] = powers[2] - (TYPE)1, a[3] = powers[3] … | |
| 32 (img[C] += nnpow(*buf, powers[C]), aux[C] += nnpow(*buf, a[C])… | |
| 33 /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 … | |
| 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_… | |
| 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… | |
| 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 < ELEMENTS… | |
| 63 FINALISE_SUBCELL… | |
| 64 j = 0;\ | |
| 65 ewriteall(STDOUT_FILENO,… | |
| 66 }\ | |
| 67 first = 0;\ | |
| 68 if (power_file && !eread_frame(&… | |
| 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->pt… | |
| 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), "<std… | |
| 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… | |
| 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", … | |
| 156 | |
| 157 if (DPRINTF_HEAD(STDOUT_FILENO, stream.frames, 1, 1, stream.pixf… | |
| 158 eprintf("dprintf:"); | |
| 159 process(&stream); | |
| 160 if (stream.ptr) | |
| 161 eprintf("%s: incomplete frame\n", stream.file); | |
| 162 return 0; | |
| 163 } |