From dc549357af9af5240ec1684efc990d2b3c337b9b Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Mon, 29 Aug 2016 02:52:02 +0300 Subject: initial commit --- .gitignore | 1 + LICENSE.txt | 21 +++++++++++ gaussian.py | 71 +++++++++++++++++++++++++++++++++++++ img/Lenna.png | Bin 0 -> 473831 bytes mean.py | 61 ++++++++++++++++++++++++++++++++ shift.py | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 266 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 gaussian.py create mode 100644 img/Lenna.png create mode 100644 mean.py create mode 100644 shift.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b44ef38 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/*.png diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..80c5e0a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Egor Tensin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/gaussian.py b/gaussian.py new file mode 100644 index 0000000..743b70d --- /dev/null +++ b/gaussian.py @@ -0,0 +1,71 @@ +# Copyright 2016 (c) Egor Tensin +# This file is part of the "Simple image filters" project. +# For details, see https://github.com/egor-tensin/filters. +# Distributed under the MIT License. + +import argparse +import sys + +import cv2 +import numpy as np + +def gen_kernel(radius, sigma): + kernel = np.array([[i ** 2 + j ** 2 + for i in range(-radius, radius + 1)] + for j in range(-radius, radius + 1)]) + kernel = -kernel / (2 * sigma ** 2) + kernel = np.exp(kernel) + kernel = kernel / np.sum(kernel) + return kernel + +def convolve(img, kernel): + #print(kernel) + radius = kernel.shape[0] // 2 + output = np.zeros(img.shape, dtype=img.dtype) + for i in range(radius, img.shape[0] - radius): + for j in range(radius, img.shape[1] - radius): + neighborhood = img[i - radius:i + radius + 1, j - radius:j + radius + 1] + output[i, j] = np.sum(neighborhood * kernel) + return output + +DEFAULT_SIGMA = 1. +DEFAULT_RADIUS = 1 + +def do(img_path, radius=DEFAULT_RADIUS, sigma=DEFAULT_SIGMA, + output_path=None): + + img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) + kernel = gen_kernel(radius, sigma) + output = convolve(img, kernel) + if output_path is None: + cv2.imshow("Output", output) + cv2.waitKey() + else: + cv2.imwrite(output_path, output) + +def _parse_non_negative_integer(s): + try: + x = int(s) + except ValueError: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + s) + if x < 0: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + s) + return x + +def _parse_args(args=sys.argv): + parser = argparse.ArgumentParser() + parser.add_argument('img_path') + parser.add_argument('--output', '-o', + dest='output_path', default=None) + parser.add_argument('-s', '--sigma', + type=float, default=DEFAULT_SIGMA) + parser.add_argument('--radius', '-r', + type=_parse_non_negative_integer, + default=DEFAULT_RADIUS) + return parser.parse_args(args[1:]) + +def main(args=sys.argv): + do(**vars(_parse_args(args))) + +if __name__ == '__main__': + main() diff --git a/img/Lenna.png b/img/Lenna.png new file mode 100644 index 0000000..59ef68a Binary files /dev/null and b/img/Lenna.png differ diff --git a/mean.py b/mean.py new file mode 100644 index 0000000..6b09eda --- /dev/null +++ b/mean.py @@ -0,0 +1,61 @@ +# Copyright 2016 (c) Egor Tensin +# This file is part of the "Simple image filters" project. +# For details, see https://github.com/egor-tensin/filters. +# Distributed under the MIT License. + +import argparse +import sys + +import cv2 +import numpy as np + +def gen_kernel(radius): + size = radius * 2 + 1 + return np.ones((size, size)) / size ** 2 + +def convolve(img, kernel): + #print(kernel) + radius = kernel.shape[0] // 2 + output = np.zeros(img.shape, dtype=img.dtype) + for i in range(radius, img.shape[0] - radius): + for j in range(radius, img.shape[1] - radius): + neighborhood = img[i - radius:i + radius + 1, j - radius:j + radius + 1] + output[i, j] = np.sum(kernel * neighborhood) + return output + +DEFAULT_RADIUS = 1 + +def do(img_path, radius=DEFAULT_RADIUS, output_path=None): + img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) + kernel = gen_kernel(radius) + output = convolve(img, kernel) + if output_path is None: + cv2.imshow("Output", output) + cv2.waitKey() + else: + cv2.imwrite(output_path, output) + +def _parse_non_negative_integer(s): + try: + x = int(s) + except ValueError: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + s) + if x < 0: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + s) + return x + +def _parse_args(args=sys.argv): + parser = argparse.ArgumentParser() + parser.add_argument('img_path') + parser.add_argument('--output', '-o', + dest='output_path', default=None) + parser.add_argument('--radius', '-r', + type=_parse_non_negative_integer, + default=DEFAULT_RADIUS) + return parser.parse_args(args[1:]) + +def main(args=sys.argv): + do(**vars(_parse_args(args))) + +if __name__ == '__main__': + main() diff --git a/shift.py b/shift.py new file mode 100644 index 0000000..76ca09a --- /dev/null +++ b/shift.py @@ -0,0 +1,112 @@ +# Copyright 2016 (c) Egor Tensin +# This file is part of the "Simple image filters" project. +# For details, see https://github.com/egor-tensin/filters. +# Distributed under the MIT License. + +import argparse +from enum import Enum +import sys + +import cv2 +import numpy as np + +class Direction(Enum): + N = 'N' + NE = 'NE' + E = 'E' + SE = 'SE' + S = 'S' + SW = 'SW' + W = 'W' + NW = 'NW' + + def gen_kernel(self, distance): + radius = distance + size = 2 * radius + 1 + kernel = np.zeros((size, size)) + x, y = radius, radius + + if self is Direction.N: + x = -1 + elif self is Direction.NE: + x, y = -1, 0 + elif self is Direction.E: + y = 0 + elif self is Direction.SE: + x, y = 0, 0 + elif self is Direction.S: + x = 0 + elif self is Direction.SW: + x, y = 0, -1 + elif self is Direction.W: + y = -1 + elif self is Direction.NW: + x, y = -1, -1 + else: + raise NotImplementedError('unsupported direction: ' + str(self)) + + kernel[x, y] = 1 + return kernel + + def __str__(self): + return self.name + +def convolve(img, kernel): + #print(kernel) + radius = kernel.shape[0] // 2 + output = np.zeros(img.shape, dtype=img.dtype) + for i in range(radius, img.shape[0] - radius): + for j in range(radius, img.shape[1] - radius): + neighborhood = img[i - radius:i + radius + 1, j - radius:j + radius + 1] + output[i, j] = np.sum(neighborhood * kernel) + return output + +DEFAULT_DIRECTION = Direction.SE +DEFAULT_DISTANCE = 1 + +def do(img_path, direction=DEFAULT_DIRECTION, distance=DEFAULT_DISTANCE, + output_path=None): + + img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) + kernel = direction.gen_kernel(distance) + output = convolve(img, kernel) + if output_path is None: + cv2.imshow("Output", output) + cv2.waitKey() + else: + cv2.imwrite(output_path, output) + +def _parse_direction(s): + try: + return Direction(s) + except ValueError: + raise argparse.ArgumentTypeError('invalid direction: ' + s) + +def _parse_non_negative_integer(s): + try: + x = int(s) + except ValueError: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + s) + if x < 0: + raise argparse.ArgumentTypeError('must be a non-negative integer: ' + s) + return x + +def _parse_args(args=sys.argv): + parser = argparse.ArgumentParser() + parser.add_argument('img_path') + parser.add_argument('--output', '-o', + dest='output_path', default=None) + parser.add_argument('--direction', '-d', + type=_parse_direction, + choices=Direction, + default=DEFAULT_DIRECTION) + parser.add_argument('--distance', '-n', + type=_parse_non_negative_integer, + default=DEFAULT_DISTANCE) + return parser.parse_args(args[1:]) + +def main(args=sys.argv): + do(**vars(_parse_args(args))) + +if __name__ == '__main__': + main() -- cgit v1.2.3