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 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 }