commit ebe2e88b44f46e59bdefef1eb585078d5fa6d4d4
Author:     Mattias Andrée <[email protected]>
AuthorDate: Sat Jul 22 19:33:54 2017 +0200
Commit:     Mattias Andrée <[email protected]>
CommitDate: Sat Jul 22 19:33:54 2017 +0200

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

diff --git a/Makefile b/Makefile
index 4149e9e..1d55cf8 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ include $(CONFIGFILE)
 
 BIN =\
        blind-affine-colour\
+       blind-apply-kernel\
        blind-apply-palette\
        blind-arithm\
        blind-cat-cols\
diff --git a/README b/README
index aa02360..9b67e6f 100644
--- a/README
+++ b/README
@@ -15,6 +15,12 @@ UTILITIES
        blind-affine-colour(1)
               Apply an affine transformation to the colours in a video
 
+       blind-apply-kernel(1)
+              Apply a convolution matrix to a video
+
+       blind-apply-palette(1)
+              Apply a colour palette to a video
+
        blind-arithm(1)
               Perform simple arithmetic on a video
 
diff --git a/TODO b/TODO
index 4d35da5..d05c941 100644
--- a/TODO
+++ b/TODO
@@ -4,7 +4,6 @@ blind-primary-key       replace a primary with transparency, -g 
for greyscaled images
 blind-colour-matrix    create colour space conversion matrix
 blind-apply-map                remap pixels (distortion) using the X and Y 
values, -[xy] for tiling, -s for
                                improve quality on downscaling (pixels' 
neighbours must not change)
-blind-apply-kernel     apply a convolution matrix.
 blind-find-frame       a graphical tool for locating frames, should highlight 
key frames, and
                                play audio. Should support both regular videos 
files and uivf
                                finding key frames: ffprobe -show_frames (lists 
all frames)
diff --git a/man/blind-apply-kernel.1 b/man/blind-apply-kernel.1
new file mode 100644
index 0000000..f09cc6e
--- /dev/null
+++ b/man/blind-apply-kernel.1
@@ -0,0 +1,69 @@
+.TH BLIND-APPLY-KERNEL 1 blind
+.SH NAME
+blind-apply-kernel - Apply a convolution matrix to a video
+.SH SYNOPSIS
+.B blind-apply-kernel
+[-apPxy]
+.I kernel-stream
+.SH DESCRIPTION
+.B blind-apply-kernel
+reads a video from stdin and a convolution matrix video
+from
+.I kernel-stream
+and apply the convolution matrix in each frame the
+same frame in stdin, and prints the resulting video
+to stdout.
+.SH OPTIONS
+.TP
+.B -a
+Used to optimise performance if it is known that
+the video is opaque, and to ensure that the output
+video is opaque.
+.TP
+.B -p
+Each frame in
+.I kernel-stream
+shall contain one matrix per pixel in a frame in
+stdin. The width of
+.I kernel-stream
+shall be a multiple of the width of stdin, the width
+shall be the width of stdin multiplied by the width
+of the convolution matrix. The height of
+.I kernel-stream
+shall be a multiple of the height of stdin, the
+height shall be the height of stdin multiplied by the
+height of the convolution matrix.
+.TP
+.B -P
+Apply the convolution with first premultiplying
+the alpha channel.
+.TP
+.B -x
+When encountering the left or right edge of the video,
+wrap around to the opposite edge.
+.TP
+.B -y
+When encountering the upper or lower edge of the video,
+wrap around to the opposite edge.
+.SH REQUIREMENTS
+.B blind-apply-kernel
+requires enough free memory to load two full frames
+from stdin and one full frame from
+.I kernel-stream
+into memory. However, if
+.I -p
+is used, the height of
+.I kernel-stream
+divide by the height of stdin number of rows from
+.I kernel-stream
+rather than a full frame from
+.I kernel-stream
+is loaded into memory.
+A frame or row requires 32 bytes per pixel it contains.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-make-kernel (1),
+.BR blind-gauss-blur (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < [email protected] >
diff --git a/man/blind-gauss-blur.1 b/man/blind-gauss-blur.1
index 652a5e5..e0e84a9 100644
--- a/man/blind-gauss-blur.1
+++ b/man/blind-gauss-blur.1
@@ -79,7 +79,9 @@ memory. A frame requires 32 bytes per pixel it contains.
 .SH SEE ALSO
 .BR blind (7),
 .BR blind-single-colour (1),
-.BR blind-time-blur (1)
+.BR blind-time-blur (1),
+.BR blind-make-kernel (1),
+.BR blind-apply-kernel (1)
 .SH AUTHORS
 Mattias Andrée
 .RI < [email protected] >
diff --git a/man/blind.7 b/man/blind.7
index 1e61ee3..b6ce62d 100644
--- a/man/blind.7
+++ b/man/blind.7
@@ -22,6 +22,12 @@ first convert it with
 .BR blind-affine-colour (1)
 Apply an affine transformation to the colours in a video
 .TP
+.BR blind-apply-kernel (1)
+Apply a convolution matrix to a video
+.TP
+.BR blind-apply-palette (1)
+Apply a colour palette to a video
+.TP
 .BR blind-arithm (1)
 Perform simple arithmetic on a video
 .TP
diff --git a/src/blind-affine-colour.c b/src/blind-affine-colour.c
index 88fd76a..7be9ab6 100644
--- a/src/blind-affine-colour.c
+++ b/src/blind-affine-colour.c
@@ -113,6 +113,8 @@ PROCESS(struct stream *colour, struct stream *matrix)
        } while (eread_stream(colour, SIZE_MAX));
        if (colour->ptr)
                eprintf("%s: incomplete frame\n", colour->file);
+
+       free(mbuf);
 }
 
 #endif
diff --git a/src/blind-apply-kernel.c b/src/blind-apply-kernel.c
new file mode 100644
index 0000000..6c00ab7
--- /dev/null
+++ b/src/blind-apply-kernel.c
@@ -0,0 +1,159 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef TYPE
+#include "common.h"
+
+USAGE("[-apPxy] kernel-stream")
+
+static int no_alpha = 0;
+static int dont_premultiply = 0;
+static int per_pixel = 0;
+static int wrap_x = 0;
+static int wrap_y = 0;
+static size_t kern_w;
+static size_t kern_h;
+
+#define FILE "blind-apply-kernel.c"
+#include "define-functions.h"
+
+int
+main(int argc, char *argv[])
+{
+       struct stream colour, kernel;
+       void (*process)(struct stream *colour, struct stream *kernel);
+       size_t tmp;
+
+       ARGBEGIN {
+       case 'a':
+               no_alpha = 1;
+               break;
+       case 'p':
+               per_pixel = 1;
+               break;
+       case 'P':
+               dont_premultiply = 1;
+               break;
+       case 'x':
+               wrap_x = 1;
+               break;
+       case 'y':
+               wrap_y = 1;
+               break;
+       default:
+               usage();
+       } ARGEND;
+
+       if (argc != 1)
+               usage();
+
+       eopen_stream(&colour, NULL);
+       eopen_stream(&kernel, argv[0]);
+
+       SELECT_PROCESS_FUNCTION(&colour);
+       if (colour.encoding != kernel.encoding || colour.n_chan != 
kernel.n_chan)
+               eprintf("videos use incompatible pixel formats");
+       if (per_pixel && !(kernel.width % colour.width || kernel.height % 
colour.height))
+               eprintf("-p is specified but the dimensions of kernel-stream "
+                       "are not multiples of the dimensions of stdin.");
+
+       kern_w = per_pixel ? kernel.width  / colour.width  : kernel.width;
+       kern_h = per_pixel ? kernel.height / colour.height : kernel.height;
+
+       tmp = kernel.height, kernel.height = kern_h;
+       echeck_dimensions(&colour, WIDTH | HEIGHT, NULL);
+       echeck_dimensions(&kernel, WIDTH | HEIGHT, NULL);
+       kernel.height = tmp;
+
+       fprint_stream_head(stdout, &colour);
+       efflush(stdout, "<stdout>");
+       process(&colour, &kernel);
+       return 0;
+}
+
+#else
+
+static void
+PROCESS(struct stream *colour, struct stream *kernel)
+{
+       TYPE *out, *clr, *krn, *kern, *pix;
+       size_t i, x, y, n, x2, y2;
+       ssize_t cx, cy, xoff, yoff;
+
+       out = emalloc(colour->frame_size);
+       clr = emalloc(colour->frame_size);
+       krn = emalloc2(kern_h, kernel->row_size);
+
+       xoff = (ssize_t)(kern_w / 2);
+       yoff = (ssize_t)(kern_h / 2);
+
+       n = colour->width * colour->height * colour->n_chan;
+       while (eread_frame(colour, clr)) {
+               /* premultiply */
+               if (!no_alpha && !dont_premultiply) {
+                       for (i = 0; i < n; i += 4) {
+                               clr[i + 0] *= clr[i + 3];
+                               clr[i + 1] *= clr[i + 3];
+                               clr[i + 2] *= clr[i + 3];
+                       }
+               }
+
+               /* apply kernel */
+               memset(out, 0, colour->frame_size);
+               pix = out;
+               for (y = 0; y < colour->height; y++) {
+                       if ((!y || per_pixel) && !eread_segment(kernel, krn, 
kern_h * kernel->row_size))
+                               goto done;
+                       for (x = 0; x < colour->width; x++, pix += 
colour->n_chan) {
+                               kern = per_pixel ? (krn + x * kern_w * 
kernel->n_chan) : krn;
+                               for (y2 = 0; y2 < kern_h; y2++, kern += 
kernel->width * kernel->n_chan) {
+                                       cy = (ssize_t)(y + y2) - yoff;
+                                       if (cy < 0 || (size_t)cy >= 
colour->height) {
+                                               if (!wrap_y)
+                                                       continue;
+                                               cy %= (ssize_t)(colour->height);
+                                               if (cy < 0)
+                                                       cy += 
(ssize_t)(colour->height);
+                                       }
+                                       for (x2 = 0; x2 < kern_w; x2++) {
+                                               cx = (ssize_t)(x + x2) - xoff;
+                                               if (cx < 0 || (size_t)cx >= 
colour->width) {
+                                                       if (!wrap_x)
+                                                               continue;
+                                                       cx %= 
(ssize_t)(colour->width);
+                                                       if (cx < 0)
+                                                               cx += 
(ssize_t)(colour->width);
+                                               }
+                                               for (i = 0; i < colour->n_chan; 
i++)
+                                                       pix[i] += kern[x2 * 
kernel->n_chan + i] *
+                                                                 
clr[((size_t)cy * colour->width + (size_t)cx) * colour->n_chan + i];
+                                       }
+                               }
+                       }
+               }
+
+               /* unpremultiply */
+               if (!dont_premultiply) {
+                       for (i = 0; i < n; i += 4) {
+                               if (out[i + 3]) {
+                                       out[i + 0] /= out[i + 3];
+                                       out[i + 1] /= out[i + 3];
+                                       out[i + 2] /= out[i + 3];
+                               }
+                       }
+               }
+
+               /* ensure video is opaque if -a was used */
+               if (no_alpha)
+                       for (i = 0; i < n; i += 4)
+                               out[i + 3] = 1;
+
+               /* output video */
+               ewriteall(STDOUT_FILENO, out, colour->frame_size, "<stdout>");
+       }
+done:
+
+       free(out);
+       free(clr);
+       free(krn);
+}
+
+#endif

Reply via email to