compton-convgen: Misc: Clean up

compton-convgen: Misc: Clean up. The commit brings no change to the
functionality of the script.

 - Partially fix PEP 8 compliance:

   - Place imports on separate lines.

   - Replace leading tabs with 4 spaces.

   - Add docstrings to classes and functions.

   - Surround top-level function and class definitions with two blank
     lines.

   - Remove spaces around keyword arguments.

   - Move all statements to separate lines.

   - Break some long lines into several lines.

 - Remove trailing semicolons after statements.

 - CGError: Use functionality from the base class Exception to store the
   description, instead of the custom logic.

 - CGInternal: Remove, as it is unused.

 - Hide the internal function gen_invalid() and args_readfactors() by
   prefixing their names with an underscore.

 - Move the module-level command-line handling code to two new
   functions, _main() and _parse_args(), and only execute if running in
   the main scope.
This commit is contained in:
Richard Grenville 2016-08-10 23:43:44 +08:00
parent 2343e4bbd2
commit f1cd308cde
1 changed files with 132 additions and 103 deletions

View File

@ -1,17 +1,22 @@
#! /usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
import math, argparse import math
import argparse
class CGError(Exception): class CGError(Exception):
def __init__(self, value): '''An error in the convolution kernel generator.'''
self.value = value def __init__(self, desc):
def __str__(self): super().__init__(desc)
return repr(self.value)
class CGBadArg(CGError):
'''An exception indicating an invalid argument has been passed to the
convolution kernel generator.'''
pass
class CGBadArg(CGError): pass
class CGInternal(CGError): pass
def mbuild(width, height): def mbuild(width, height):
"""Build a NxN matrix filled with 0.""" """Build a NxN matrix filled with 0."""
@ -22,37 +27,42 @@ def mbuild(width, height):
result[i].append(0.0) result[i].append(0.0)
return result return result
def mdump(matrix): def mdump(matrix):
"""Dump a matrix in natural format.""" """Dump a matrix in natural format."""
for col in matrix: for col in matrix:
print("[ ", end = ''); print("[ ", end='')
for ele in col: for ele in col:
print(format(ele, "13.6g") + ", ", end = " ") print(format(ele, "13.6g") + ", ", end=" ")
print("],") print("],")
def mdumpcompton(matrix): def mdumpcompton(matrix):
"""Dump a matrix in compton's format.""" """Dump a matrix in compton's format."""
width = len(matrix[0]) width = len(matrix[0])
height = len(matrix) height = len(matrix)
print("{},{},".format(width, height), end = '') print("{},{},".format(width, height), end='')
for i in range(height): for i in range(height):
for j in range(width): for j in range(width):
if int(height / 2) == i and int(width / 2) == j: if int(height / 2) == i and int(width / 2) == j:
continue; continue
print(format(matrix[i][j], ".6f"), end = ",") print(format(matrix[i][j], ".6f"), end=",")
print() print()
def mnormalize(matrix): def mnormalize(matrix):
"""Scale a matrix according to the value in the center.""" """Scale a matrix according to the value in the center."""
width = len(matrix[0]) width = len(matrix[0])
height = len(matrix) height = len(matrix)
factor = 1.0 / matrix[int(height / 2)][int(width / 2)] factor = 1.0 / matrix[int(height / 2)][int(width / 2)]
if 1.0 == factor: return matrix if 1.0 == factor:
return matrix
for i in range(height): for i in range(height):
for j in range(width): for j in range(width):
matrix[i][j] *= factor matrix[i][j] *= factor
return matrix return matrix
def mmirror4(matrix): def mmirror4(matrix):
"""Do a 4-way mirroring on a matrix from top-left corner.""" """Do a 4-way mirroring on a matrix from top-left corner."""
width = len(matrix[0]) width = len(matrix[0])
@ -64,6 +74,7 @@ def mmirror4(matrix):
matrix[i][j] = matrix[x][y] matrix[i][j] = matrix[x][y]
return matrix return matrix
def gen_gaussian(width, height, factors): def gen_gaussian(width, height, factors):
"""Build a Gaussian blur kernel.""" """Build a Gaussian blur kernel."""
@ -76,14 +87,17 @@ def gen_gaussian(width, height, factors):
result = mbuild(size, size) result = mbuild(size, size)
for i in range(int(size / 2) + 1): for i in range(int(size / 2) + 1):
for j in range(int(size / 2) + 1): for j in range(int(size / 2) + 1):
diffx = i - int(size / 2); diffx = i - int(size / 2)
diffy = j - 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)) result[i][j] = 1.0 / (2 * math.pi * sigma) \
* pow(math.e, - (diffx * diffx + diffy * diffy) \
/ (2 * sigma * sigma))
mnormalize(result) mnormalize(result)
mmirror4(result) mmirror4(result)
return result return result
def gen_box(width, height, factors): def gen_box(width, height, factors):
"""Build a box blur kernel.""" """Build a box blur kernel."""
result = mbuild(width, height) result = mbuild(width, height)
@ -92,10 +106,13 @@ def gen_box(width, height, factors):
result[i][j] = 1.0 result[i][j] = 1.0
return result return result
def gen_invalid(width, height, factors):
def _gen_invalid(width, height, factors):
'''Handle a convolution kernel generation request of an unrecognized type.'''
raise CGBadArg("Unknown kernel type.") raise CGBadArg("Unknown kernel type.")
def args_readfactors(lst):
def _args_readfactors(lst):
"""Parse the factor arguments.""" """Parse the factor arguments."""
factors = dict() factors = dict()
if lst: if lst:
@ -108,25 +125,37 @@ def args_readfactors(lst):
factors[res[0]] = float(res[2]) factors[res[0]] = float(res[2])
return factors 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 def _parse_args():
height = args.height '''Parse the command-line arguments.'''
if not height:
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.')
return parser.parse_args()
def _main():
args = _parse_args()
width = args.width
height = args.height
if not height:
height = width height = width
if not (width > 0 and height > 0): if not (width > 0 and height > 0):
raise CGBadArg("Invalid width/height.") raise CGBadArg("Invalid width/height.")
factors = args_readfactors(args.factor) factors = _args_readfactors(args.factor)
funcs = dict(gaussian = gen_gaussian, box = gen_box) funcs = dict(gaussian=gen_gaussian, box=gen_box)
matrix = (funcs.get(args.type, gen_invalid))(width, height, factors) matrix = (funcs.get(args.type, _gen_invalid))(width, height, factors)
if args.dump_compton: if args.dump_compton:
mdumpcompton(matrix) mdumpcompton(matrix)
else: else:
mdump(matrix) mdump(matrix)
if __name__ == '__main__':
_main()