From a3f6f4442bae0437d4ac3048e27df976ded35155 Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Mon, 29 Apr 2013 22:42:46 +0800 Subject: [PATCH] Improvement: Add predefined blur kernels - Add a few predefined blur kernels, requested by jerri in #104. - Add compton-convgen.py to generate blur kernels. --- bin/compton-convgen.py | 132 +++++++++++++++++++++++++++++++++++++++++ src/compton.c | 30 +++++++++- 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100755 bin/compton-convgen.py diff --git a/bin/compton-convgen.py b/bin/compton-convgen.py new file mode 100755 index 00000000..ab745d12 --- /dev/null +++ b/bin/compton-convgen.py @@ -0,0 +1,132 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +# vim:fileencoding=utf-8 + +import math, argparse + +class CGError(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +class CGBadArg(CGError): pass +class CGInternal(CGError): pass + +def mbuild(width, height): + """Build a NxN matrix filled with 0.""" + result = list() + for i in range(height): + result.append(list()) + for j in range(width): + result[i].append(0.0) + return result + +def mdump(matrix): + """Dump a matrix in natural format.""" + for col in matrix: + print("[ ", end = ''); + for ele in col: + print(format(ele, "13.6g") + ", ", end = " ") + print("],") + +def mdumpcompton(matrix): + """Dump a matrix in compton's format.""" + width = len(matrix[0]) + height = len(matrix) + print("{},{},".format(width, height), end = '') + for i in range(height): + for j in range(width): + if int(height / 2) == i and int(width / 2) == j: + continue; + print(format(matrix[i][j], ".6f"), end = ",") + print() + +def mnormalize(matrix): + """Scale a matrix according to the value in the center.""" + width = len(matrix[0]) + height = len(matrix) + factor = 1.0 / matrix[int(height / 2)][int(width / 2)] + if 1.0 == factor: return matrix + for i in range(height): + for j in range(width): + matrix[i][j] *= factor + return matrix + +def mmirror4(matrix): + """Do a 4-way mirroring on a matrix from top-left corner.""" + width = len(matrix[0]) + height = len(matrix) + for i in range(height): + for j in range(width): + x = min(i, height - 1 - i) + y = min(j, width - 1 - j) + matrix[i][j] = matrix[x][y] + return matrix + +def gen_gaussian(width, height, factors): + """Build a Gaussian blur kernel.""" + + if width != height: + raise CGBadArg("Cannot build an uneven Gaussian blur kernel.") + + size = width + sigma = float(factors.get('sigma', 0.84089642)) + + result = mbuild(size, size) + for i in range(int(size / 2) + 1): + for j in range(int(size / 2) + 1): + diffx = i - int(size / 2); + diffy = j - int(size / 2); + result[i][j] = 1.0 / (2 * math.pi * sigma) * pow(math.e, - (diffx * diffx + diffy * diffy) / (2 * sigma * sigma)) + mnormalize(result) + mmirror4(result) + + return result + +def gen_box(width, height, factors): + """Build a box blur kernel.""" + result = mbuild(width, height) + for i in range(height): + for j in range(width): + result[i][j] = 1.0 + return result + +def gen_invalid(width, height, factors): + raise CGBadArg("Unknown kernel type.") + +def args_readfactors(lst): + """Parse the factor arguments.""" + factors = dict() + if lst: + for s in lst: + res = s.partition('=') + if not res[0]: + raise CGBadArg("Factor has no key.") + if not res[2]: + raise CGBadArg("Factor has no value.") + factors[res[0]] = float(res[2]) + return factors + +parser = argparse.ArgumentParser(description='Build a convolution kernel.') +parser.add_argument('type', help='Type of convolution kernel. May be "gaussian" (factor sigma = 0.84089642) or "box".') +parser.add_argument('width', type=int, help='Width of convolution kernel. Must be an odd number.') +parser.add_argument('height', nargs='?', type=int, help='Height of convolution kernel. Must be an odd number. Equals to width if omitted.') +parser.add_argument('-f', '--factor', nargs='+', help='Factors of the convolution kernel, in name=value format.') +parser.add_argument('--dump-compton', action='store_true', help='Dump in compton format.') +args = parser.parse_args() + +width = args.width +height = args.height +if not height: + height = width +if not (width > 0 and height > 0): + raise CGBadArg("Invalid width/height.") +factors = args_readfactors(args.factor) + +funcs = dict(gaussian = gen_gaussian, box = gen_box) +matrix = (funcs.get(args.type, gen_invalid))(width, height, factors) +if args.dump_compton: + mdumpcompton(matrix) +else: + mdump(matrix) diff --git a/src/compton.c b/src/compton.c index a97ca17c..82ee6c71 100644 --- a/src/compton.c +++ b/src/compton.c @@ -4237,6 +4237,9 @@ usage(void) { " --blur-background-fixed.\n" " A 7x7 Guassian blur kernel looks like:\n" " --blur-kern '7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003'\n" + " May also be one the predefined kernels: 3x3box (default), 5x5box,\n" + " 7x7box, 3x3gaussian, 5x5gaussian, 7x7gaussian, 9x9gaussian,\n" + " 11x11gaussian.\n" "--blur-background-exclude condition\n" " Exclude conditions for background blur.\n" "--resize-damage integer\n" @@ -4589,6 +4592,31 @@ parse_matrix_err: return NULL; } +/** + * Parse a convolution kernel. + */ +static inline XFixed * +parse_conv_kern(session_t *ps, const char *src) { + static const struct { + const char *name; + const char *kern_str; + } CONV_KERN_PREDEF[] = { + { "3x3box", "3,3,1,1,1,1,1,1,1,1," }, + { "5x5box", "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, + { "7x7box", "7,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, + { "3x3gaussian", "3,3,0.243117,0.493069,0.243117,0.493069,0.493069,0.243117,0.493069,0.243117," }, + { "5x5gaussian", "5,5,0.003493,0.029143,0.059106,0.029143,0.003493,0.029143,0.243117,0.493069,0.243117,0.029143,0.059106,0.493069,0.493069,0.059106,0.029143,0.243117,0.493069,0.243117,0.029143,0.003493,0.029143,0.059106,0.029143,0.003493," }, + { "7x7gaussian", "7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003," }, + { "9x9gaussian", "9,9,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000," }, + { "11x11gaussian", "11,11,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000," }, + }; + for (int i = 0; + i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) + if (!strcmp(CONV_KERN_PREDEF[i].name, src)) + return parse_matrix(ps, CONV_KERN_PREDEF[i].kern_str); + return parse_matrix(ps, src); +} + /** * Parse a condition list in configuration file. */ @@ -5097,7 +5125,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { case 301: // --blur-kern free(ps->o.blur_kern); - if (!(ps->o.blur_kern = parse_matrix(ps, optarg))) + if (!(ps->o.blur_kern = parse_conv_kern(ps, optarg))) exit(1); case 302: // --resize-damage