blind-temporal-mean.c (5440B)
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, void *buffer, void *image, size_t frame); 9 10 /* 11 * X-parameter 1: method enum value 12 * X-parameter 2: identifier-friendly name 13 * X-parameter 3: images 14 * X-parameter 4: action for first frame 15 * X-parameter 5: pre-process assignments 16 * X-parameter 6: subcell processing 17 * X-parameter 7: pre-finalise assignments 18 * X-parameter 8: subcell finalisation 19 */ 20 #define LIST_MEANS(TYPE)\ 21 /* [default] arithmetic mean */\ 22 X(ARITHMETIC, arithmetic, 1, COPY_FRAME,, *img += *buf,\ 23 a = (TYPE)1 / (TYPE)frame, *img *= a)\ 24 /* standard deviation */\ 25 X(STANDARD_DEVIATION, sd, 2, ZERO_AND_PROCESS_FRAME,, (*img += *buf * *buf, *aux += *buf),\ 26 a = (TYPE)1 / (TYPE)frame, *img = nnpow((*img - *aux * *aux * a) * a, (TYPE)0.5))\ 27 /* geometric mean */\ 28 X(GEOMETRIC, geometric, 1, COPY_FRAME,, *img *= *buf,\ 29 a = (TYPE)1 / (TYPE)frame, *img = nnpow(*img, a))\ 30 /* harmonic mean */\ 31 X(HARMONIC, harmonic, 1, ZERO_AND_PROCESS_FRAME,, *img += (TYPE)1 / *buf,\ 32 a = (TYPE)frame, *img = a / *img)\ 33 /* Lehmer mean */\ 34 X(LEHMER, lehmer, 2, ZERO_AND_PROCESS_FRAME,,\ 35 (*img += nnpow(*buf, *pows), *aux += nnpow(*buf, *pows - (TYPE)1)),, *img /= *aux)\ 36 /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\ 37 X(POWER, power, 1, ZERO_AND_PROCESS_FRAME,, *img += nnpow(*buf, *pows),\ 38 a = (TYPE)1 / (TYPE)frame, *img = a * nnpow(*img, (TYPE)1 / *pows))\ 39 /* variance */\ 40 X(VARIANCE, variance, 2, ZERO_AND_PROCESS_FRAME,, (*img += *buf * *buf, *aux += *buf),\ 41 a = (TYPE)1 / (TYPE)frame, *img = (*img - *aux * *aux * a) * a) 42 43 enum first_frame_action { 44 COPY_FRAME, 45 PROCESS_FRAME, 46 ZERO_AND_PROCESS_FRAME, 47 }; 48 49 #define X(V, ...) V, 50 enum method { LIST_MEANS() }; 51 #undef X 52 53 static void *powerbuf = NULL; 54 55 #define MAKE_PROCESS(PIXFMT, TYPE,\ 56 _1, NAME, _3, _4, PRE_PROCESS, PROCESS_SUBCELL, PRE_FINALISE, FINALISE_SUBCELL)\ 57 static void\ 58 process_##PIXFMT##_##NAME(struct stream *stream, void *buffer, void *image, size_t frame)\ 59 {\ 60 TYPE *buf = buffer, *img = image, a, *pows = powerbuf;\ 61 TYPE *aux = (TYPE *)(((char *)image) + stream->frame_size);\ 62 size_t x, y, z;\ 63 if (!buf) {\ 64 PRE_FINALISE;\ 65 for (z = 0; z < stream->n_chan; z++)\ 66 for (y = 0; y < stream->height; y++)\ 67 for (x = 0; x < stream->width; x++, img++, aux++, pows++)\ 68 FINALISE_SUBCELL;\ 69 } else {\ 70 PRE_PROCESS;\ 71 for (z = 0; z < stream->n_chan; z++)\ 72 for (y = 0; y < stream->height; y++)\ 73 for (x = 0; x < stream->width; x++, img++, aux++, pows++, buf++) { \ 74 PROCESS_SUBCELL;\ 75 }\ 76 }\ 77 (void) aux, (void) a, (void) pows, (void) frame;\ 78 } 79 #define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__) 80 LIST_MEANS(double) 81 #undef X 82 #define X(...) MAKE_PROCESS(f, float, __VA_ARGS__) 83 LIST_MEANS(float) 84 #undef X 85 #undef MAKE_PROCESS 86 87 #define X(ID, NAME, ...) [ID] = process_lf_##NAME, 88 static const process_func process_functions_lf[] = { LIST_MEANS() }; 89 #undef X 90 91 #define X(ID, NAME, ...) [ID] = process_f_##NAME, 92 static const process_func process_functions_f[] = { LIST_MEANS() }; 93 #undef X 94 95 int 96 main(int argc, char *argv[]) 97 { 98 struct stream stream, power; 99 void *buf, *img; 100 process_func process; 101 size_t frames, images; 102 enum method method = ARITHMETIC; 103 enum first_frame_action first_frame_action; 104 const char *power_file = NULL; 105 106 ARGBEGIN { 107 case 'd': 108 method = STANDARD_DEVIATION; 109 break; 110 case 'g': 111 method = GEOMETRIC; 112 break; 113 case 'h': 114 method = HARMONIC; 115 break; 116 case 'l': 117 method = LEHMER; 118 power_file = UARGF(); 119 break; 120 case 'p': 121 method = POWER; 122 power_file = UARGF(); 123 break; 124 case 'v': 125 method = VARIANCE; 126 break; 127 default: 128 usage(); 129 } ARGEND; 130 131 if (argc) 132 usage(); 133 134 #define X(ID, _2, IMAGES, FIRST_FRAME_ACTION, ...)\ 135 case ID:\ 136 images = IMAGES;\ 137 first_frame_action = FIRST_FRAME_ACTION;\ 138 break; 139 switch (method) { 140 LIST_MEANS() 141 default: 142 abort(); 143 } 144 #undef X 145 146 eopen_stream(&stream, NULL); 147 if (power_file != NULL) { 148 eopen_stream(&power, power_file); 149 echeck_compat(&stream, &power); 150 powerbuf = emalloc(power.frame_size); 151 if (!eread_frame(&power, powerbuf)) 152 eprintf("%s is no frames\n", power_file); 153 } 154 155 if (stream.encoding == DOUBLE) 156 process = process_functions_lf[method]; 157 else if (stream.encoding == FLOAT) 158 process = process_functions_f[method]; 159 else 160 eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); 161 162 stream.frames = 1; 163 echeck_dimensions(&stream, WIDTH | HEIGHT, NULL); 164 fprint_stream_head(stdout, &stream); 165 efflush(stdout, "<stdout>"); 166 buf = emalloc(stream.frame_size); 167 if (first_frame_action == ZERO_AND_PROCESS_FRAME) 168 img = ecalloc(images, stream.frame_size); 169 else 170 img = emalloc2(images, stream.frame_size); 171 172 frames = 0; 173 if (first_frame_action == COPY_FRAME) { 174 if (!eread_frame(&stream, img)) 175 eprintf("video is no frames\n"); 176 frames++; 177 } 178 for (; eread_frame(&stream, buf); frames++) 179 process(&stream, buf, img, frames); 180 if (!frames) 181 eprintf("video has no frames\n"); 182 process(&stream, NULL, img, frames); 183 184 ewriteall(STDOUT_FILENO, img, stream.frame_size, "<stdout>"); 185 free(buf); 186 free(img); 187 free(powerbuf); 188 return 0; 189 }