Sleds/imagine-cv/cv-resize.py

385 lines
12 KiB
Python

#!/usr/bin/python
import cv2
import argparse
import sys
import os
import time
import string
import ConsoleUtils
# I like timing things
_START_TIME = time.time()
name = 'OCVResize'
description = 'A tool for resizing images using the OpenCV library.'
author = 'Chris Diesch <cdiesch@sequencelogic.net>'
version = '0.1.0'
date = '2017/09/25'
usage = 'imagine-cv [OPTIONS...] -i,--input IN_PATH -o,--output OUT_PATH'
args = None
# Verbosity
_VERBOSE = None
_QUIET = None
# Input type
_USE_DIR = None
# Output format
_OUT_NAME_FORMAT = None
# Image color
_G_SCALE = None
# Image size options
_NEW_Y = None
_NEW_X = None
_IMG_SCALE = None
_INTER = cv2.INTER_CUBIC
_INTER_NAME = 'Cubic'
# name formatting tags
_IN_NAME = '${in_file}'
_Y_VAL = '${new_y}'
_X_VAL = '${new_x}'
parser = argparse.ArgumentParser(prog=name, description=description, add_help=False, usage=usage)
printer = ConsoleUtils.SLPrinter(name)
# Helper methods
def _format_name(in_name):
template_str = string.Template(_OUT_NAME_FORMAT)
mapping = {'in_file': in_name, 'new_y': _NEW_Y, 'new_x': _NEW_X}
result = template_str.safe_substitute(mapping)
return result
def _resize_and_save_img(img_file, out_file):
global _NEW_X, _NEW_Y
if _VERBOSE:
print('Reading image from %s' % img_file)
image = cv2.imread(img_file)
if _G_SCALE:
if _VERBOSE:
print('Converting image to gray scale')
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
if _VERBOSE:
print('Processing image %s' % img_file)
src_y, src_x = image.shape[:2]
# Get the scale factors
if _IMG_SCALE == 0:
x_scale = 1
y_scale = 1
if _NEW_X != 0:
x_scale = float(float(_NEW_X) / src_x)
if _NEW_Y != 0:
y_scale = float(float(_NEW_Y) / src_y)
if x_scale == 1:
x_scale = y_scale
_NEW_X = src_x * x_scale
elif y_scale == 1:
y_scale = x_scale
_NEW_Y = src_y * y_scale
else:
x_scale = _IMG_SCALE
y_scale = _IMG_SCALE
_NEW_Y = _IMG_SCALE * src_y
_NEW_X = _IMG_SCALE * src_x
# logging
if _VERBOSE:
print('Source image size: %dx%d' % (src_y, src_x))
print('X scale factor: %f' % x_scale)
print('Y scale factor: %f' % y_scale)
print('New Size: %dx%d' % (_NEW_Y, _NEW_X))
image = cv2.resize(image, None, fx=x_scale, fy=y_scale, interpolation=_INTER)
if _VERBOSE:
print('Saving image to "%s"' % out_file)
cv2.imwrite(out_file, image)
def _process_images(image_dir, output_dir):
start_time = time.time()
images = os.listdir(image_dir)
num_processed = 0
num_images = len(images)
if not _QUIET:
print('Loaded %d images to process' % num_images)
for img in images:
# get the image name
img_name = _format_name(img)
img = os.path.join(image_dir, img)
new_img = os.path.join(output_dir, img_name)
# resize the image
_resize_and_save_img(img, new_img)
# logging...
if _VERBOSE and num_processed % 10 == 0:
img_per_sec = float(num_processed/(time.time() - start_time))
print('Processed %d images (rate: %.4f/s)' % (num_processed, img_per_sec))
# Increment
num_processed += 1
# more logging
if not _QUIET:
run_time = time.time() - start_time
img_per_sec = float(num_images/run_time)
print('Processed %d images in %.4f seconds (%.2f images/s)' % (num_images, run_time, img_per_sec))
def _process_single_img(input_file, output_file):
if _VERBOSE:
print('Processing image "%s"' % input_file)
start_time = time.time()
_resize_and_save_img(input_file, output_file)
run_time = time.time() - start_time
if not _QUIET:
print('Processed image in %.4f seconds.' % run_time)
# Main
def main(input_dir, output):
if _USE_DIR:
_process_images(input_dir, output)
else:
_process_single_img(input_dir, output)
# Everything below this is application set up/argument processing this code is where the global values referenced
# above are defined and input arguments are validated.
# Application helpers
def _print_version():
printer.write_no_prefix(name)
printer.write_no_prefix('Version: %s' % version)
printer.write_no_prefix('Date: %s' % date)
printer.write_no_prefix('Author: %s' % author)
def _print_help():
sys.stdout = printer.old_stdout
print(name)
print(description)
print('Usage: %s' % usage)
print('')
print('Options')
print(' Required:')
print(' -i, --input IN_PATH The path to the input image.')
print(' -o, --output OUT_PATH The path to save the new image to.')
print(' NOTE: images will be saved as ".png" files.')
print('')
print(' Input/Output:')
print(' -n, --name-format FORMAT Use this format when naming images '
'(default: "${input}(${new_h}).jpg").')
print(' NOTE: --output MUST be a directory when using this option.')
print(' Valid format tags:')
print(' - ${input} Replaced with the name of the input file.')
print(' - ${new_h} Replaced with the new HEIGHT value (pixels).')
print(' - ${new_w} Replaced with the new WIDTH value (pixels).')
print('')
print(' Image Color:')
print(' -g, --grey-scale Convert the image to grey scale.')
print('')
print(' Image Resizing:')
print(' -s, --scale SCALE Use this value as the scale factor for both X and Y values (float).')
print(' NOTE: This CANNOT be used with WIDTH or HEIGHT arguments.')
print(' -w, --img-width WIDTH Set the image width to WIDTH (pixels).')
print(' If this value is <= 0, the image will maintain it\'s proportions')
print(' and the new size will be determined by the height argument.')
print(' -h, --img-height HEIGHT Set the image height to HEIGHT (pixels).')
print(' If this value is <= 0, the image will maintain it\'s proportions.')
print(' and the new size will be determined by the width argument.')
print(' -c, --cubic Use cubic interpolation (default).')
print(' -l, --linear Use linear interpolation.')
print(' -a, --area Yse area interpolation.')
print('')
print(' Miscellaneous:')
print(' -h, --help Prints the help message.')
print(' -V, --version Prints the version information.')
print(' -v, --verbose Increases the output verbosity (console logging).')
print(' -q, --quiet Reduces the output verbosity (console logging).')
print('')
print('Version Information:')
print(' Version: %s' % version)
print(' Date: %s' % date)
print('')
print('Author: %s' % author)
def _make_args():
# Required arguments
required_args = parser.add_argument_group('Required')
required_args.add_argument('-i', '--input', required=True)
required_args.add_argument('-o', '--output', required=True)
# Input/Output arguments
in_out_args = parser.add_argument_group('Input/Output')
in_out_args.add_argument('-n', '--name-format', default='${in_file}(${new_y}).jpg')
# Color arguments
color_args = parser.add_argument_group('Image Color')
color_args.add_argument('-g', '--gray-scale', action='store_true')
# Size arguments
size_args = parser.add_argument_group('Image Resizing')
size_args.add_argument('-s', '--scale', type=float, default=0)
size_args.add_argument('-w', '--img-width', type=int, default=0)
size_args.add_argument('-H', '--img-height', type=int, default=0)
inter_arg = size_args.add_mutually_exclusive_group()
inter_arg.add_argument('-c', '--cubic', action='store_true')
inter_arg.add_argument('-l', '--linear', action='store_true')
inter_arg.add_argument('-a', '--area', action='store_true')
# Miscellaneous arguments
misc_args = parser.add_argument_group('Miscellaneous')
misc_args.add_argument('-V', '--version', action=ConsoleUtils.CustomPrintAction, print_fn=_print_version)
misc_args.add_argument('-h', '--help', action=ConsoleUtils.CustomPrintAction, print_fn=_print_help)
v_or_q = misc_args.add_mutually_exclusive_group()
v_or_q.add_argument('-v', '--verbose', action="store_true")
v_or_q.add_argument("-q", "--quiet", action="store_true")
def _show_args():
if not _QUIET:
print('Loading image(s) from path: "%s"' % args.input)
print('Saving output(s) to path: "%s"' % args.output)
print('Loading from directories: %s' % _USE_DIR)
print('Using Interpolation method: "%s"' % _INTER_NAME)
if _NEW_Y != 0:
print('Result image height: %d' % _NEW_Y)
if _NEW_X != 0:
print('Result image width: %d' % _NEW_X)
if _IMG_SCALE != 0:
print('Scaling images by factor: %f' % _IMG_SCALE)
print('Convert to grey scale: %s' % _G_SCALE)
print('Image name format: "%s"' % _OUT_NAME_FORMAT)
printer.write_no_prefix('')
def _check_args():
fatal_error = False
if args.scale != 0 and (args.img_width != 0 or args.img_height != 0):
print('Fatal Error: Values were provided for "--scale" and "--height" or "--width" arguments.')
print('If you wish to use the "--scale" argument, you cannot use "--height" or "--width".')
fatal_error = True
if not os.path.exists(args.input):
print('Fatal Error: The given input file does not exist (%s)' % args.input)
fatal_error = True
if not os.path.exists(args.output) and _USE_DIR:
print('Error: The given output directory does not exist (%s)')
print('Attempting to create path "%s"')
try:
os.makedirs(args.output)
print('Successfully created output path "%s"' % args.output)
except BaseException as ex:
print('Fatal Error: Unable to create output path at "%s"' % args.output)
print(ex)
fatal_error = True
if args.img_height == 0 and args.img_width == 0 and args.scale == 0:
print('Fatal Error: No valid resizing value given')
fatal_error = True
if not args.linear and not args.area:
args.cubic = True
if fatal_error:
printer.write_no_prefix('')
_print_help()
print('Exiting...')
exit(1)
def _set_inter():
global _INTER, _INTER_NAME
if args.linear:
_INTER = cv2.INTER_LINEAR
_INTER_NAME = 'Linear'
elif args.area:
_INTER = cv2.INTER_AREA
_INTER_NAME = 'Area'
else:
_INTER = cv2.INTER_CUBIC
_INTER_NAME = 'Cubic'
def _set_dir():
global _USE_DIR
_USE_DIR = os.path.isdir(args.input)
def _set_in_out():
global _OUT_NAME_FORMAT
_OUT_NAME_FORMAT = args.name_format
def _set_verbosity():
global _VERBOSE, _QUIET
_VERBOSE = args.verbose
_QUIET = args.quiet
def _set_size():
global _NEW_X, _NEW_Y, _IMG_SCALE
_NEW_Y = args.img_height
_NEW_X = args.img_width
_IMG_SCALE = args.scale
def _set_color():
global _G_SCALE
_G_SCALE = args.gray_scale
# Setup function
def setup():
global args
print(ConsoleUtils.get_header(name, version, date, author))
sys.stdout = printer
_make_args()
args = parser.parse_args()
# get some arguments first...
_set_verbosity()
_set_dir()
_set_inter()
_set_size()
_set_color()
_set_in_out()
# validate the arguments
_check_args()
# Show the valid arguments...
_show_args()
# Cleanup function
def cleanup(err=False):
run_time = time.time() - _START_TIME
if not err:
print('Successfully Completed in %.4f s' % run_time)
else:
print('Application encountered an error %.4f s into processing.' % run_time)
# Executes main
if __name__ == '__main__':
exception = False
setup()
try:
main(args.input, args.output)
except:
ConsoleUtils.print_exception()
exception = True
cleanup(exception)