blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | 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 }