Improvement: Add predefined blur kernels
- Add a few predefined blur kernels, requested by jerri in #104. - Add compton-convgen.py to generate blur kernels.
This commit is contained in:
parent
abd559c512
commit
a3f6f4442b
|
@ -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)
|
|
@ -4237,6 +4237,9 @@ usage(void) {
|
||||||
" --blur-background-fixed.\n"
|
" --blur-background-fixed.\n"
|
||||||
" A 7x7 Guassian blur kernel looks like:\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"
|
" --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"
|
"--blur-background-exclude condition\n"
|
||||||
" Exclude conditions for background blur.\n"
|
" Exclude conditions for background blur.\n"
|
||||||
"--resize-damage integer\n"
|
"--resize-damage integer\n"
|
||||||
|
@ -4589,6 +4592,31 @@ parse_matrix_err:
|
||||||
return NULL;
|
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.
|
* 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:
|
case 301:
|
||||||
// --blur-kern
|
// --blur-kern
|
||||||
free(ps->o.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);
|
exit(1);
|
||||||
case 302:
|
case 302:
|
||||||
// --resize-damage
|
// --resize-damage
|
||||||
|
|
Loading…
Reference in New Issue