diff --git a/fourcell/common.py b/fourcell/common.py new file mode 100644 index 0000000..d2d8994 --- /dev/null +++ b/fourcell/common.py @@ -0,0 +1,122 @@ +import cv2 +import math + +def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA): + dim = None + (h, w) = image.shape[:2] + + if width is None and height is None: + return image + + if width is None: + r = height / float(h) + dim = (int(w * r), height) + else: + r = width / float(w) + dim = (width, int(h * r)) + resized = cv2.resize(image, dim, interpolation = inter) + + return resized + +def display (image) : + resized = image_resize(image, 800, 800) + cv2.imshow('img', resized) + + while cv2.getWindowProperty('img', cv2.WND_PROP_VISIBLE) > 0: + key = cv2.waitKey(0) + if key == 27: + cv2.destroyAllWindows() + break + exit(0) + +# taken from +# https://gist.github.com/phn/1111712/35e8883de01916f64f7f97da9434622000ac0390 +def normalize_angle (num, lower=0.0, upper=360.0, b=False): + """Normalize number to range [lower, upper) or [lower, upper]. + Parameters + ---------- + num : float + The number to be normalized. + lower : float + Lower limit of range. Default is 0.0. + upper : float + Upper limit of range. Default is 360.0. + b : bool + Type of normalization. See notes. + Returns + ------- + n : float + A number in the range [lower, upper) or [lower, upper]. + Raises + ------ + ValueError + If lower >= upper. + Notes + ----- + If the keyword `b == False`, the default, then the normalization + is done in the following way. Consider the numbers to be arranged + in a circle, with the lower and upper marks sitting on top of each + other. Moving past one limit, takes the number into the beginning + of the other end. For example, if range is [0 - 360), then 361 + becomes 1. Negative numbers move from higher to lower + numbers. So, -1 normalized to [0 - 360) becomes 359. + If the keyword `b == True` then the given number is considered to + "bounce" between the two limits. So, -91 normalized to [-90, 90], + becomes -89, instead of 89. In this case the range is [lower, + upper]. This code is based on the function `fmt_delta` of `TPM`. + Range must be symmetric about 0 or lower == 0. + Examples + -------- + >>> normalize(-270,-180,180) + 90 + >>> import math + >>> math.degrees(normalize(-2*math.pi,-math.pi,math.pi)) + 0.0 + >>> normalize(181,-180,180) + -179 + >>> normalize(-180,0,360) + 180 + >>> normalize(36,0,24) + 12 + >>> normalize(368.5,-180,180) + 8.5 + >>> normalize(-100, -90, 90, b=True) + -80.0 + >>> normalize(100, -90, 90, b=True) + 80.0 + >>> normalize(181, -90, 90, b=True) + -1.0 + >>> normalize(270, -90, 90, b=True) + -90.0 + """ + # abs(num + upper) and abs(num - lower) are needed, instead of + # abs(num), since the lower and upper limits need not be 0. We need + # to add half size of the range, so that the final result is lower + + # or upper - , respectively. + res = num + if not b: + if lower >= upper: + raise ValueError("Invalid lower and upper limits: (%s, %s)" % + (lower, upper)) + + res = num + if num > upper or num == lower: + num = lower + abs(num + upper) % (abs(lower) + abs(upper)) + if num < lower or num == upper: + num = upper - abs(num - lower) % (abs(lower) + abs(upper)) + + res = lower if res == upper else num + else: + total_length = abs(lower) + abs(upper) + if num < -total_length: + num += math.ceil(num / (-2 * total_length)) * 2 * total_length + if num > total_length: + num -= math.floor(num / (2 * total_length)) * 2 * total_length + if num > upper: + num = total_length - num + if num < lower: + num = -total_length - num + + res = num * 1.0 # Make all numbers float, to be consistent + + return res \ No newline at end of file diff --git a/fourcell/normalize.py b/fourcell/normalize.py index a232bca..b795d9b 100644 --- a/fourcell/normalize.py +++ b/fourcell/normalize.py @@ -2,34 +2,11 @@ import sys import cv2 import numpy as np import math +from os.path import exists +from common import image_resize, display, normalize_angle -def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA): - dim = None - (h, w) = image.shape[:2] - - if width is None and height is None: - return image - - if width is None: - r = height / float(h) - dim = (int(w * r), height) - else: - r = width / float(w) - dim = (width, int(h * r)) - resized = cv2.resize(image, dim, interpolation = inter) - - return resized - -def display (image) : - resized = image_resize(image, 800, 800) - cv2.imshow('img', resized) - - while cv2.getWindowProperty('img', cv2.WND_PROP_VISIBLE) > 0: - key = cv2.waitKey(0) - if key == 27: - cv2.destroyAllWindows() - break - exit(0) +#clockwise from top left +order = [ 1, 3, 4, 6, 5, 2 ] def get_center (contour) : M = cv2.moments(contour) @@ -61,98 +38,6 @@ def is_close (point, points) : return True return False -# taken from -# https://gist.github.com/phn/1111712/35e8883de01916f64f7f97da9434622000ac0390 -def normalize_angle (num, lower=0.0, upper=360.0, b=False): - """Normalize number to range [lower, upper) or [lower, upper]. - Parameters - ---------- - num : float - The number to be normalized. - lower : float - Lower limit of range. Default is 0.0. - upper : float - Upper limit of range. Default is 360.0. - b : bool - Type of normalization. See notes. - Returns - ------- - n : float - A number in the range [lower, upper) or [lower, upper]. - Raises - ------ - ValueError - If lower >= upper. - Notes - ----- - If the keyword `b == False`, the default, then the normalization - is done in the following way. Consider the numbers to be arranged - in a circle, with the lower and upper marks sitting on top of each - other. Moving past one limit, takes the number into the beginning - of the other end. For example, if range is [0 - 360), then 361 - becomes 1. Negative numbers move from higher to lower - numbers. So, -1 normalized to [0 - 360) becomes 359. - If the keyword `b == True` then the given number is considered to - "bounce" between the two limits. So, -91 normalized to [-90, 90], - becomes -89, instead of 89. In this case the range is [lower, - upper]. This code is based on the function `fmt_delta` of `TPM`. - Range must be symmetric about 0 or lower == 0. - Examples - -------- - >>> normalize(-270,-180,180) - 90 - >>> import math - >>> math.degrees(normalize(-2*math.pi,-math.pi,math.pi)) - 0.0 - >>> normalize(181,-180,180) - -179 - >>> normalize(-180,0,360) - 180 - >>> normalize(36,0,24) - 12 - >>> normalize(368.5,-180,180) - 8.5 - >>> normalize(-100, -90, 90, b=True) - -80.0 - >>> normalize(100, -90, 90, b=True) - 80.0 - >>> normalize(181, -90, 90, b=True) - -1.0 - >>> normalize(270, -90, 90, b=True) - -90.0 - """ - # abs(num + upper) and abs(num - lower) are needed, instead of - # abs(num), since the lower and upper limits need not be 0. We need - # to add half size of the range, so that the final result is lower + - # or upper - , respectively. - res = num - if not b: - if lower >= upper: - raise ValueError("Invalid lower and upper limits: (%s, %s)" % - (lower, upper)) - - res = num - if num > upper or num == lower: - num = lower + abs(num + upper) % (abs(lower) + abs(upper)) - if num < lower or num == upper: - num = upper - abs(num - lower) % (abs(lower) + abs(upper)) - - res = lower if res == upper else num - else: - total_length = abs(lower) + abs(upper) - if num < -total_length: - num += math.ceil(num / (-2 * total_length)) * 2 * total_length - if num > total_length: - num -= math.floor(num / (2 * total_length)) * 2 * total_length - if num > upper: - num = total_length - num - if num < lower: - num = -total_length - num - - res = num * 1.0 # Make all numbers float, to be consistent - - return res - def mean (lst): return sum(lst) / len(lst) @@ -395,6 +280,10 @@ def normalize_image(blank, rotated, offset, tl) : return blank +# +# NORMALIZE +# + if len(sys.argv) < 2: print('Please provide path of scan to normalize') exit(1) @@ -404,6 +293,11 @@ if len(sys.argv) < 3: exit(2) scanImage = sys.argv[-2] + +if not exists(scanImage) : + print('Scan provided does not exist') + exit(5) + normalImage = sys.argv[-1] pageDim = (11, 8.5) pageRatio = pageDim[1] / pageDim[0]