blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit bd8018a737281770159231c060f3bfd30788a430
parent 835df7bd1e81852062dd70ce1a054fc9b510e50f
Author: Mattias Andrée <maandree@kth.se>
Date:   Wed, 26 Jul 2017 00:24:39 +0200

Add blind-mean

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Makefile | 1+
README | 3+++
TODO | 9++-------
man/blind-arithm.1 | 1+
man/blind-mean.1 | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/blind-spatial-arithm.1 | 1+
man/blind-spatial-mean.1 | 3++-
man/blind-temporal-arithm.1 | 1+
man/blind-temporal-mean.1 | 1+
man/blind.7 | 3+++
src/blind-mean.c | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-spatial-mean.c | 2+-
src/blind-temporal-mean.c | 2+-
13 files changed, 275 insertions(+), 10 deletions(-)

diff --git a/Makefile b/Makefile @@ -53,6 +53,7 @@ BIN =\ blind-matrix-shear\ blind-matrix-translate\ blind-matrix-transpose\ + blind-mean\ blind-mosaic\ blind-mosaic-corners\ blind-mosaic-edges\ diff --git a/README b/README @@ -156,6 +156,9 @@ UTILITIES blind-matrix-transpose(1) Create an affine 2D-transformation matrix for transposition + blind-mean(1) + Calcuate the mean over videos for each pixel in each frame + blind-mosaic(1) Redraw each frame in video as a mosaic diff --git a/TODO b/TODO @@ -1,3 +1,5 @@ +blind-*-mean: replace power with power-stream + blind-transform affine transformation by matrix multiplication, -[xy] for tiling, -s for improve quality on downscaling (pixels' neighbours must not change) blind-apply-map remap pixels (distortion) using the X and Y values, -[xy] for tiling, -s for @@ -24,13 +26,6 @@ blind-roberts-cross https://en.wikipedia.org/wiki/Roberts_cross --- https://en.wikipedia.org/wiki/Canny_edge_detector --- https://en.wikipedia.org/wiki/Deriche_edge_detector --- https://en.wikipedia.org/wiki/Edge_detection -blind-mean mean of multiple streams - means from blind-temporal-mean - https://en.wikipedia.org/wiki/Heinz_mean - https://en.wikipedia.org/wiki/Heronian_mean - https://en.wikipedia.org/wiki/Identric_mean - https://en.wikipedia.org/wiki/Logarithmic_mean - https://en.wikipedia.org/wiki/Stolarsky_mean blind-apply-icc apply ICC profile to video blind-convex-gradient create a gradient in the shape of a convex lens blind-concave-gradient create a gradient in the shape of a concave lens diff --git a/man/blind-arithm.1 b/man/blind-arithm.1 @@ -100,6 +100,7 @@ Do not modify the Z channel (the third channel). .BR blind-spatial-arithm (1), .BR blind-temporal-mean (1), .BR blind-temporal-arithm (1), +.BR blind-mean (1), .BR blind-single-colour (1), .BR blind-set-alpha (1), .BR blind-set-luma (1), diff --git a/man/blind-mean.1 b/man/blind-mean.1 @@ -0,0 +1,87 @@ +.TH BLIND-MEAN 1 blind +.SH NAME +blind-mean - Calcuate the mean over videos for each pixel in each frame +.SH SYNOPSIS +.B blind-mean +[-g | -h | -H | -i | -l +.I power +| -L | -p +.I power +| -s +.I power +| -v | -z +.IR power ] +.I stream-1 +.IR stream-2 \ ... +.SH DESCRIPTION +.B blind-mean +reads videos from +.I stream-1 +and the files specified in all succeeding +arguments, and for each pixel in each frame, +calculates the mean of the videos, and prints +the resulting video to stdout. +.P +Unless otherwise specified, the arithmetic mean +is calculated. +.SH OPTIONS +.TP +.B -g +Calculate the geometric mean. +.TP +.B -h +Calculate the harmonic mean. +.TP +.B -i +Calculate the identric mean. +.TP +.B -H +Calculate the Heronian mean. +No arguments after +.I stream-2 +are allowed if this flag is used. +.TP +.BR -l \ \fIpower\fP +Calculate the Lehmer mean with the specified +.IR power . +.TP +.B -L +Calculate the logarithmic mean. +No arguments after +.I stream-2 +are allowed if this flag is used. +.TP +.BR -p \ \fIpower\fP +Calculate the power mean (Hölder mean) with +the specified +.IR power . +.TP +.BR -s \ \fIpower\fP +Calculate the Stolarsky mean with +the specified +.IR power . +No arguments after +.I stream-2 +are allowed if this flag is used. +.TP +.B -v +Calculate the variance. +.TP +.BR -z \ \fIpower\fP +Calculate the Heinz meanw ith +the specified +.IR power . +No arguments after +.I stream-2 +are allowed if this flag is used. +.SH SEE ALSO +.BR blind (7), +.BR blind-temporal-mean (1), +.BR blind-spatial-mean (1), +.BR blind-temporal-arithm (1), +.BR blind-spatial-arithm (1), +.BR blind-arithm (1), +.BR blind-rewrite-head (1) +.SH AUTHORS +Mattias Andrée +.RI < maandree@kth.se > diff --git a/man/blind-spatial-arithm.1 b/man/blind-spatial-arithm.1 @@ -29,6 +29,7 @@ Select the highest operand. .BR blind-arithm (1), .BR blind-spatial-mean (1), .BR blind-temporal-mean (1), +.BR blind-mean (1), .BR blind-rewrite-head (1) .SH AUTHORS Mattias Andrée diff --git a/man/blind-spatial-mean.1 b/man/blind-spatial-mean.1 @@ -38,10 +38,11 @@ the specified Calculate the variance. .SH SEE ALSO .BR blind (7), +.BR blind-temporal-mean (1), +.BR blind-mean (1), .BR blind-temporal-arithm (1), .BR blind-spatial-arithm (1), .BR blind-arithm (1), -.BR blind-temporal-mean (1), .BR blind-rewrite-head (1) .SH AUTHORS Mattias Andrée diff --git a/man/blind-temporal-arithm.1 b/man/blind-temporal-arithm.1 @@ -33,6 +33,7 @@ A frame requires 32 bytes per pixel it contains. .BR blind-spatial-arithm (1), .BR blind-spatial-mean (1), .BR blind-arithm (1), +.BR blind-mean (1), .BR blind-rewrite-head (1) .SH AUTHORS Mattias Andrée diff --git a/man/blind-temporal-mean.1 b/man/blind-temporal-mean.1 @@ -54,6 +54,7 @@ is optimised for simplicity rather than memory usage. .BR blind-spatial-arithm (1), .BR blind-arithm (1), .BR blind-spatial-mean (1), +.BR blind-mean (1), .BR blind-rewrite-head (1) .SH AUTHORS Mattias Andrée diff --git a/man/blind.7 b/man/blind.7 @@ -174,6 +174,9 @@ Create an affine 2D-transformation matrix for translation .BR blind-matrix-transpose (1) Create an affine 2D-transformation matrix for transposition .TP +.BR blind-mean (1) +Calcuate the mean over videos for each pixel in each frame +.TP .BR blind-mosaic (1) Redraw each frame in video as a mosaic .TP diff --git a/src/blind-mean.c b/src/blind-mean.c @@ -0,0 +1,171 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-g | -h | -H | -i | -l power | -L | -p power | -s power | -v | -z power] stream-1 stream-2 ...") +/* TODO add [-w weight-stream] for [-ghlpv] */ + +/* Because the syntax for a function returning a function pointer is disgusting. */ +typedef void (*process_func)(struct stream *streams, size_t n_streams, size_t n); + +/* + * X-parameter 1: method enum value + * X-parameter 2: identifier-friendly name + * X-parameter 3: initial assignments + * X-parameter 4: initial value + * X-parameter 5: subcell processing + * X-parameter 6: subcell finalisation + */ +#define LIST_MEANS(TYPE)\ + /* [default] arithmetic mean */\ + X(ARITHMETIC, arithmetic, sn = (TYPE)1 / sn, 0, img += val, img *= sn) \ + /* geometric mean */\ + X(GEOMETRIC, geometric, sn = (TYPE)1 / sn, 1, img *= val, img = nnpow(img, sn))\ + /* harmonic mean */\ + X(HARMONIC, harmonic,, 0, img += (TYPE)1 / val, img = sn / img)\ + /* Heronian mean */\ + X(HERONIAN, heronian,, 0, auxs[j] = val,\ + img = (auxs[0] + sqrt(auxs[0] * auxs[1]) + auxs[1]) / (TYPE)3)\ + /* identric mean */\ + X(IDENTRIC, identric, a = (TYPE)(1. / M_E), 0, auxs[j] = val,\ + img = auxs[0] == auxs[1] ? auxs[0] :\ + nnpow(nnpow(auxs[0], auxs[0]) / nnpow(auxs[1], auxs[1]), auxs[0] - auxs[1]) * a)\ + /* Lehmer mean */\ + X(LEHMER, lehmer, (a = (TYPE)power, b = a - (TYPE)1), 0,\ + (img += nnpow(val, a), aux += nnpow(val, b)), img /= aux)\ + /* logarithmic mean */\ + X(LOGARITHMIC, logarithmic,, 0, auxs[j] = val,\ + img = auxs[0] == auxs[1] ? auxs[0] : (!auxs[0] || !auxs[1]) ? (TYPE)0 :\ + (auxs[1] - auxs[0]) / log(auxs[1] / auxs[0]))\ + /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\ + X(POWER, power, (a = (TYPE)power, b = (TYPE)(1. / power), sn = (TYPE)1 / sn), 0,\ + img += nnpow(val, a), img = nnpow(img, b) * sn)\ + /* Stolarsky mean */\ + X(STOLARSKY, stolarsky, (a = (TYPE)power, b = (TYPE)(1. / (power - 1.))), 0, auxs[j] = val,\ + img = auxs[0] == auxs[1] ? auxs[0] :\ + nnpow((nnpow(auxs[0], auxs[0]) - nnpow(auxs[1], auxs[1])) /\ + (a * (auxs[0] - auxs[1])), b))\ + /* variance */\ + X(VARIANCE, variance, sn = (TYPE)1 / sn, 0, (img += val * val, aux += val),\ + img = (img - aux * aux * sn) * sn)\ + /* Heinz mean */\ + X(HEINZ, heinz, (a = (TYPE)power, b = (TYPE)1 - a), 0, auxs[j] = val,\ + img = (nnpow(auxs[0], a) * nnpow(auxs[1], b) + nnpow(auxs[0], b) * nnpow(auxs[1], 0)) / (TYPE)2) + +#define X(V, ...) V, +enum method { LIST_MEANS() }; +#undef X + +static double power; + +#define aux (*auxs) +#define MAKE_PROCESS(PIXFMT, TYPE,\ + _1, NAME, INIT, INITIAL, PROCESS_SUBCELL, FINALISE_SUBCELL)\ + static void\ + process_##PIXFMT##_##NAME(struct stream *streams, size_t n_streams, size_t n)\ + {\ + size_t i, j;\ + TYPE img, auxs[2], val, a, b, sn = (TYPE)n_streams;\ + INIT;\ + for (i = 0; i < n; i += sizeof(TYPE)) {\ + img = auxs[0] = auxs[1] = INITIAL;\ + for (j = 0; j < n_streams; j++) {\ + val = *(TYPE *)(streams[j].buf + i);\ + PROCESS_SUBCELL;\ + }\ + FINALISE_SUBCELL;\ + *(TYPE *)(streams->buf + i) = img;\ + }\ + (void) aux, (void) a, (void) b, (void) sn;\ + } +#define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__) +LIST_MEANS(double) +#undef X +#define X(...) MAKE_PROCESS(f, float, __VA_ARGS__) +LIST_MEANS(float) +#undef X +#undef MAKE_PROCESS +#undef aux + +#define X(ID, NAME, ...) [ID] = process_lf_##NAME, +static const process_func process_functions_lf[] = { LIST_MEANS() }; +#undef X + +#define X(ID, NAME, ...) [ID] = process_f_##NAME, +static const process_func process_functions_f[] = { LIST_MEANS() }; +#undef X + +int +main(int argc, char *argv[]) +{ + struct stream *streams; + process_func process; + size_t frames = SIZE_MAX, tmp; + enum method method = ARITHMETIC; + int i, two = 0; + + ARGBEGIN { + case 'g': + method = GEOMETRIC; + break; + case 'h': + method = HARMONIC; + break; + case 'H': + method = HERONIAN; + two = 1; + break; + case 'i': + method = IDENTRIC; + two = 1; + break; + case 'l': + method = LEHMER; + power = etolf_flag('l', UARGF()); + break; + case 'L': + method = LOGARITHMIC; + two = 1; + break; + case 'p': + method = POWER; + power = etolf_flag('p', UARGF()); + break; + case 's': + method = STOLARSKY; + two = 1; + power = etolf_flag('s', UARGF()); + break; + case 'v': + method = VARIANCE; + break; + case 'z': + method = HEINZ; + two = 1; + power = etolf_flag('z', UARGF()); + break; + default: + usage(); + } ARGEND; + + if (argc < 2 || (argc > 2 && two)) + usage(); + + streams = alloca((size_t)argc * sizeof(*streams)); + for (i = 0; i < argc; i++) { + eopen_stream(streams + i, argv[i]); + if (streams[i].frames && streams[i].frames < frames) + frames = streams[i].frames; + } + + if (streams->encoding == DOUBLE) + process = process_functions_lf[method]; + else + process = process_functions_f[method]; + + tmp = streams->frames, streams->frames = frames; + fprint_stream_head(stdout, streams); + efflush(stdout, "<stdout>"); + streams->frames = tmp; + process_multiple_streams(streams, (size_t)argc, STDOUT_FILENO, "<stdout>", 1, process); + return 0; +} diff --git a/src/blind-spatial-mean.c b/src/blind-spatial-mean.c @@ -2,7 +2,7 @@ #include "common.h" USAGE("[-g | -h | -l power | -p power | -v]") -/* TODO add [-w weight-stream] for -l */ +/* TODO add [-w weight-stream] for [-ghlpv] */ /* Because the syntax for a function returning a function pointer is disgusting. */ typedef void (*process_func)(struct stream *stream); diff --git a/src/blind-temporal-mean.c b/src/blind-temporal-mean.c @@ -2,7 +2,7 @@ #include "common.h" USAGE("[-g | -h | -l power | -p power | -v]") -/* TODO add [-w weight-stream] for -l */ +/* TODO add [-w weight-stream] for [-ghlpv] */ /* Because the syntax for a function returning a function pointer is disgusting. */ typedef void (*process_func)(struct stream *stream, void *buffer, void *image, size_t frame);