commit bd8018a737281770159231c060f3bfd30788a430
Author:     Mattias Andrée <[email protected]>
AuthorDate: Wed Jul 26 00:24:39 2017 +0200
Commit:     Mattias Andrée <[email protected]>
CommitDate: Wed Jul 26 00:24:39 2017 +0200

    Add blind-mean
    
    Signed-off-by: Mattias Andrée <[email protected]>

diff --git a/Makefile b/Makefile
index 1bc0f16..cb85dd0 100644
--- 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
index f844730..6ad6865 100644
--- 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
index fb62d11..f9cfc0c 100644
--- 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
index 22d7fd7..68ce505 100644
--- 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
new file mode 100644
index 0000000..cd2b331
--- /dev/null
+++ 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 < [email protected] >
diff --git a/man/blind-spatial-arithm.1 b/man/blind-spatial-arithm.1
index f512944..1784794 100644
--- 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
index 74ffa53..315da1f 100644
--- 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
index 1ccfc2a..f4c53f6 100644
--- 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
index 88e0d0c..167c6c4 100644
--- 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
index 2e32b5e..e7fc942 100644
--- 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
new file mode 100644
index 0000000..f445d25
--- /dev/null
+++ 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
index 848af2d..b4e54e5 100644
--- 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
index 12d0cad..8c442d0 100644
--- 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);

Reply via email to