commit 9e524b9dedeeea7f5d5e39edb80c588b161deed4
parent 7be1448a633be40aadd41250f99019438af0c688
Author: Mattias Andrée <maandree@kth.se>
Date: Sun, 14 May 2017 00:23:52 +0200
Add gaussian blur and unshaping kernels
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
2 files changed, 90 insertions(+), 5 deletions(-)
diff --git a/src/blind-kernel.c b/src/blind-kernel.c
@@ -2,18 +2,20 @@
#include "stream.h"
#include "util.h"
+#include <math.h>
#include <string.h>
USAGE("[-xyza] kernel [parameter] ...")
-#define SUBUSAGE(FORMAT) "Usage: %s [-xyza] " FORMAT, argv0
-#define MATRIX(...) ((const double[]){__VA_ARGS__});
+#define SUBUSAGE(FORMAT) "Usage: %s [-xyza] " FORMAT, argv0
+#define MATRIX(...) ((const double[]){__VA_ARGS__});
#define STREQ3(A, B1, B2, B3) (!strcmp(A, B1) || !strcmp(A, B2) || !strcmp(A, B3))
#define LIST_KERNELS\
- X(kernel_kirsch, "kirsch")\
+ X(kernel_kirsch, "kirsch")\
X(kernel_box_blur, "box blur")\
- X(kernel_sharpen, "sharpen")
+ X(kernel_sharpen, "sharpen")\
+ X(kernel_gaussian, "gaussian")
static const double *
kernel_kirsch(int argc, char *argv[], size_t *rows, size_t *cols, double **free_this)
@@ -55,7 +57,7 @@ kernel_box_blur(int argc, char *argv[], size_t *rows, size_t *cols, double **fre
}
*rows = 2 * sy + 1;
*cols = 2 * sx + 1;
- *free_this = cells = emalloc2(*rows, *cols);
+ *free_this = cells = emalloc3(*rows, *cols, sizeof(double));
n = (2 * sy + 1) * (2 * sx + 1);
value = 1 / (double)n;
for (i = 0; i < n; i++)
@@ -74,6 +76,75 @@ kernel_sharpen(int argc, char *argv[], size_t *rows, size_t *cols, double **free
(void) argv;
}
+static const double *
+kernel_gaussian(int argc, char *argv[], size_t *rows, size_t *cols, double **free_this)
+{
+ size_t spread = 0, y, x;
+ int unsharpen = 0;
+ double sigma, value, c, k;
+ char *arg;
+
+#define argv0 arg
+ argc++, argv--;
+ ARGBEGIN {
+ case 's':
+ if (!(arg = ARGF()))
+ goto usage;
+ spread = etozu_flag('s', arg, 1, SIZE_MAX / 2);
+ break;
+ case 'u':
+ unsharpen = 1;
+ break;
+ } ARGEND;
+#undef argv0
+
+ if (argc != 1)
+ goto usage;
+
+ sigma = etof_arg("standard-deviation", argv[0]);
+
+ if (!spread)
+ spread = (size_t)(sigma * 3.0 + 0.5);
+ *rows = *cols = spread * 2 + 1;
+
+ *free_this = emalloc3(*rows, *cols, sizeof(double));
+
+ k = sigma * sigma * 2;
+ c = M_PI * k;
+ c = sqrt(c);
+ c = 1.0 / c;
+ k = 1.0 / -k;
+
+ for (x = 0; x <= spread; x++) {
+ value = spread - x;
+ value *= value * k;
+ value = exp(value) * c;
+ for (y = 0; y < *rows; y++) {
+ (*free_this)[y * *cols + x] = value;
+ (*free_this)[y + 1 * *cols + *cols - 1 - x] = value;
+ }
+ }
+
+ for (y = 0; y <= spread; y++) {
+ value = spread - y;
+ value *= value * k;
+ value = exp(value) * c;
+ for (x = 0; x < *cols; x++) {
+ (*free_this)[y * *cols + x] *= value;
+ (*free_this)[y + 1 * *cols + *cols - 1 - x] *= value;
+ }
+ }
+
+ if (unsharpen)
+ (*free_this)[spread * *cols + spread] -= 2.0;
+
+ return *free_this;
+
+usage:
+ eprintf(SUBUSAGE("'gaussian' [-s spread] [-u] standard-deviation"));
+ return NULL;
+}
+
int
main(int argc, char *argv[])
{
diff --git a/src/util/emalloc.h b/src/util/emalloc.h
@@ -4,12 +4,14 @@
#define emalloc(...) enmalloc(1, __VA_ARGS__)
#define emalloc2(...) enmalloc2(1, __VA_ARGS__)
+#define emalloc3(...) enmalloc3(1, __VA_ARGS__)
#define ecalloc(...) encalloc(1, __VA_ARGS__)
#define erealloc(...) enrealloc(1, __VA_ARGS__)
#define erealloc2(...) enrealloc2(1, __VA_ARGS__)
#define erealloc3(...) enrealloc3(1, __VA_ARGS__)
#define malloc2(n, m) malloc(n * m);
+#define malloc3(n1, n2, n3) malloc(n1 * n2 * n3);
#define realloc2(p, n, m) realloc(p, n * m);
#define realloc3(p, n1, n2, n3) realloc(p, n1 * n2 * n3);
@@ -32,6 +34,18 @@ enmalloc2(int status, size_t n, size_t m)
}
static inline void *
+enmalloc3(int status, size_t n1, size_t n2, size_t n3)
+{
+ void *ptr;
+ size_t n = n1;
+ if (n2 > SIZE_MAX / n ||
+ n3 > SIZE_MAX / (n *= n2) ||
+ !(ptr = malloc(n * n3)))
+ enprintf(status, "malloc: out of memory\n");
+ return ptr;
+}
+
+static inline void *
encalloc(int status, size_t n, size_t m)
{
void *ptr = calloc(n, m);