blind

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

commit 45c25008cbea5241fb711dc7a9ba21ec631bce64
parent 7903e99f22c9aa149ef1b7bcc4472cdec4a8a65f
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun, 14 May 2017 14:21:02 +0200

Fix errors in blind-kernel and add -w to box blur, and update TODO

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

Diffstat:
MTODO | 17+++++++++++++++++
Msrc/blind-kernel.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 105 insertions(+), 21 deletions(-)

diff --git a/TODO b/TODO @@ -17,6 +17,21 @@ blind-invert-chroma invert the chroma blind-from-sent convert a sent presentation to a one-frame-per-slide blind video. blind-kirsch https://en.wikipedia.org/wiki/Kirsch_operator +blind-gaussian-noise https://en.wikipedia.org/wiki/Gaussian_noise +blind-threshold https://en.wikipedia.org/wiki/Thresholding_(image_processing) +... https://en.wikipedia.org/wiki/Balanced_histogram_thresholding +blind-otsu https://en.wikipedia.org/wiki/Otsu%27s_method +blind-sobel https://en.wikipedia.org/wiki/Sobel_operator +blind-scharr https://en.wikipedia.org/wiki/Sobel_operator#Alternative_operators +blind-prewitt https://en.wikipedia.org/wiki/Prewitt_operator +blind-roberts-cross https://en.wikipedia.org/wiki/Roberts_cross +--- https://en.wikipedia.org/wiki/Foreground_detection +--- https://en.wikipedia.org/wiki/Noise_reduction#In_images +--- https://en.wikipedia.org/wiki/Dark-frame_subtraction +--- https://en.wikipedia.org/wiki/Video_denoising +--- https://en.wikipedia.org/wiki/Canny_edge_detector +--- https://en.wikipedia.org/wiki/Deriche_edge_detector +--- https://en.wikipedia.org/wiki/Edge_detection blind-from-video: add options to: * just run ffmpeg just print the output @@ -28,6 +43,8 @@ blind-from-video: add options to: Add [-j jobs] to blind-from-video and blind-to-video. +Add -f (framewise) to blind-repeat + Generate a header file with the appropriate values for USING_BINARY32, USING_BINARY64. long double is slightly faster than long. long double (xyza q) could be added as another format. diff --git a/src/blind-kernel.c b/src/blind-kernel.c @@ -8,7 +8,6 @@ USAGE("[-xyza] kernel [parameter] ...") #define SUBUSAGE(FORMAT) "Usage: %s [-xyza] " FORMAT, argv0 -#define MATRIX(...) ((const double[]){__VA_ARGS__}); #define STRCASEEQ3(A, B1, B2, B3) (!strcasecmp(A, B1) || !strcasecmp(A, B2) || !strcasecmp(A, B3)) #define LIST_KERNELS\ @@ -20,18 +19,28 @@ USAGE("[-xyza] kernel [parameter] ...") static const double * kernel_kirsch(int argc, char *argv[], size_t *rows, size_t *cols, double **free_this) { + static const double matrices[][9] = { + { 5, 5, 5, -3, 0, -3, -3, -3, -3}, + { 5, 5, -3, 5, 0, -3, -3, -3, -3}, + { 5, -3, -3, 5, 0, -3, 5, -3, -3}, + {-3, -3, -3, 5, 0, -3, 5, 5, -3}, + {-3, -3, -3, -3, 0, -3, 5, 5, 5}, + {-3, -3, -3, -3, 0, 5, -3, 5, 5}, + {-3, -3, 5, -3, 0, 5, -3, -3, 5}, + {-3, 5, 5, -3, 0, 5, -3, -3, -3}, + }; *free_this = NULL; *rows = *cols = 3; if (argc != 1) eprintf(SUBUSAGE("'kirsch' direction")); - if (STRCASEEQ3(argv[0], "1", "N", "N")) return MATRIX( 5, 5, 5, -3, 0, -3, -3, -3, -3); - if (STRCASEEQ3(argv[0], "2", "NW", "WN")) return MATRIX( 5, 5, -3, 5, 0, -3, -3, -3, -3); - if (STRCASEEQ3(argv[0], "3", "W", "W")) return MATRIX( 5, -3, -3, 5, 0, -3, 5, -3, -3); - if (STRCASEEQ3(argv[0], "4", "SW", "WS")) return MATRIX(-3, -3, -3, 5, 0, -3, 5, 5, -3); - if (STRCASEEQ3(argv[0], "5", "S", "S")) return MATRIX(-3, -3, -3, -3, 0, -3, 5, 5, 5); - if (STRCASEEQ3(argv[0], "6", "SE", "ES")) return MATRIX(-3, -3, -3, -3, 0, 5, -3, 5, 5); - if (STRCASEEQ3(argv[0], "7", "E", "E")) return MATRIX(-3, -3, 5, -3, 0, 5, -3, -3, 5); - if (STRCASEEQ3(argv[0], "8", "NE", "EN")) return MATRIX(-3, 5, 5, -3, 0, 5, -3, -3, -3); + if (STRCASEEQ3(argv[0], "1", "N", "N")) return matrices[0]; + if (STRCASEEQ3(argv[0], "2", "NW", "WN")) return matrices[1]; + if (STRCASEEQ3(argv[0], "3", "W", "W")) return matrices[2]; + if (STRCASEEQ3(argv[0], "4", "SW", "WS")) return matrices[3]; + if (STRCASEEQ3(argv[0], "5", "S", "S")) return matrices[4]; + if (STRCASEEQ3(argv[0], "6", "SE", "ES")) return matrices[5]; + if (STRCASEEQ3(argv[0], "7", "E", "E")) return matrices[6]; + if (STRCASEEQ3(argv[0], "8", "NE", "EN")) return matrices[7]; eprintf("Unrecognised direction: %s\n", argv[0]); return NULL; } @@ -39,41 +48,85 @@ kernel_kirsch(int argc, char *argv[], size_t *rows, size_t *cols, double **free_ static const double * kernel_box_blur(int argc, char *argv[], size_t *rows, size_t *cols, double **free_this) { - size_t sx, sy, i, n; - double *cells, value; + size_t sx = 1, sy = 1, i, n; + double *cells, value, weight = 0; + int have_weight = 0; + char *arg; *free_this = NULL; *rows = *cols = 3; - if (argc > 3) - eprintf(SUBUSAGE("'box blur' [spread | x-spread y-spread]")); - if (!argc) - return MATRIX(1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, - 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, - 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0); + +#define argv0 arg + argc++, argv--; + ARGBEGIN { + case 'w': + if (!(arg = ARGF())) + goto usage; + weight = etolf_flag('w', arg); + have_weight = 1; + break; + default: + goto usage; + } ARGEND; +#undef argv0 + if (argc == 1) { sx = sy = etozu_arg("spread", argv[0], 0, SIZE_MAX / 2); - } else { + } else if (argc == 2) { sx = etozu_arg("x-spread", argv[0], 0, SIZE_MAX / 2); sy = etozu_arg("y-spread", argv[1], 0, SIZE_MAX / 2); + } else if (argc) { + goto usage; } + *rows = 2 * sy + 1; *cols = 2 * sx + 1; *free_this = cells = emalloc3(*rows, *cols, sizeof(double)); + n = (2 * sy + 1) * (2 * sx + 1); value = 1 / (double)n; + if (have_weight) + value = (1.0 - weight) / (double)(n - 1); for (i = 0; i < n; i++) cells[i] = value; + if (have_weight) + cells[sy * *cols + sx] = weight; return cells; + +usage: + eprintf(SUBUSAGE("'box blur' [-w weight] [spread | x-spread y-spread]")); + return NULL; } static const double * kernel_sharpen(int argc, char *argv[], size_t *rows, size_t *cols, double **free_this) { + static const double matrices[][9] = { + { 0, -1, 0, -1, 5, -1, 0, -1, 0}, + {-1, -1, -1, -1, 9, -1, -1, -1, -1} + }; + char *arg; + int intensified = 0; *free_this = NULL; *rows = *cols = 3; + +#define argv0 arg + argc++, argv--; + ARGBEGIN { + case 'i': + intensified = 1; + break; + default: + goto usage; + } ARGEND; +#undef argv0 if (argc) - eprintf(SUBUSAGE("'sharpen'")); - return MATRIX(0, -1, 0, -1, 5, -1, 0, -1, -0); - (void) argv; + goto usage; + + return matrices[intensified]; +usage: + eprintf(SUBUSAGE("'sharpen' [-i]")); + return NULL; + (void) arg; } static const double * @@ -147,6 +200,20 @@ usage: return NULL; } +/* TODO more kernels: + Edge detection: MATRIX( 1, 0, -1, 0, 0, 0, -1, 0, 1) + Edge detection: MATRIX( 0, 1, 0, 1, -4, 1, 0, 1, 0) + Edge detection: MATRIX(-1, -1, -1, -1, 8, -1, -1, -1, -1) + Edge detection: MATRIX( 0, 0, 0, -1, 2, -1, 0, 0, 0) [H] + Edge detection: MATRIX( 0, -1, 0, 0, 2, 0, 0, -1, 0) [V] + Gradient detection: MATRIX(-1, -1, -1, 0, 0, 0, 1, 1, 1) [H] + Gradient detection: MATRIX(-1, 0, 1, -1, 0, 1, -1, 0, 1) [V] + Sobel operator: MATRIX( 1, 2, 1, 0, 0, 0, -1, -2, -1) [H] + Sobel operator: MATRIX( 1, 0, -1, 2, 0, -2, 1, 0, -1) [V] + Emboss: MATRIX(-2, -1, 0, -1, 1, 1, 0, 1, 2) + Edge enhance: MATRIX( 0, 0, 0, -1, 1, 0, 0, 0, 0) + */ + int main(int argc, char *argv[]) {