From ae58def2739802d75067ad7bb68568c03645fa85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rostislav=20L=C3=A1n?= Date: Thu, 8 Dec 2022 19:05:19 +0100 Subject: [PATCH] Reworked argument parsing, filter application, added parsing config files. --- config/config.json | 39 +++++++++++ src/main.py | 170 +++++++++++++++++++++++++++++++-------------- 2 files changed, 157 insertions(+), 52 deletions(-) create mode 100644 config/config.json diff --git a/config/config.json b/config/config.json new file mode 100644 index 0000000..80fd247 --- /dev/null +++ b/config/config.json @@ -0,0 +1,39 @@ +{ + "default": { + "inputFile": "res/img.png", + "outputFile": "res/img_done.png", + "dpi": 500, + "flip": false, + "width": 0, + "filters": [ + "gaussian", + "erode", + "blur" + ] + }, + + "test1" : { + "inputFile" : "res/test_fp.png", + "outputFile" : "res/test_fp_cpy.png", + "dpi" : 500, + "flip" : true, + "width" : 0, + "filters": [ + "gaussian" , + "erode", + "blur" + ] + }, + + "test2": { + "inputFile": "res/test_fp.png", + "outputFile": "res/test_fp_cpy.png", + "dpi": 1000, + "flip": false, + "width": 500, + "filters": [ + "gaussian", + "dilate" + ] + } +} diff --git a/src/main.py b/src/main.py index 8226387..257f4af 100644 --- a/src/main.py +++ b/src/main.py @@ -3,9 +3,13 @@ @author xlanro00 """ -# Import libraries +# Import basic libraries import argparse as ap +import configparser as cp +import sys import json + +# Libraries for image processing import numpy as np import matplotlib.pyplot as plt from PIL import Image @@ -16,76 +20,132 @@ import filters as flt class apply_filters: def __init__(self): - # Parse and save arguments. - self.parse_arguments() - self.input_file = self.args.input_file - self.output_file = self.args.output_file - self.dpi = self.args.dpi # should be around 500-1000dpi - self.filters = self.args.filters - self.flip = self.args.flip - - # Read input image, save its dimensions - self.img = plt.imread(self.input_file) - self.dimensions = self.img.shape - self.print_debug(self.dimensions) - + + if len(sys.argv) < 4: + # Parse configuration from file + print("Reading " + sys.argv[1] + + " for configuration" + sys.argv[2], file=sys.stderr) + self.conf_file = open(sys.argv[1]) + self.preset = sys.argv[2] + self.parse_conf() + else: + # Parse and save arguments. + self.parse_arguments() + self.input_file = self.args.input_file + self.output_file = self.args.output_file + self.dpi = self.args.dpi + self.filters = self.args.filters + self.flip = self.args.flip + self.conf_file = self.args.config_file if self.args.config_file else None + self.preset = self.args.preset if self.args.preset else None + self.width = self.args.width if self.args.width else 0 + # Convert dimensions + self.img = Image.open(self.input_file) self.convert_dpi() - + self.resize_image() + self.flip_image() + # Apply all filters self.apply_filter() + + def parse_conf(self): + + # Parse configuration file if given. + + self.conf = json.load(self.conf_file) + preset = self.conf[self.preset] + self.input_file = preset['inputFile'] + self.output_file = preset['outputFile'] + self.dpi = preset['dpi'] + self.filters = preset['filters'] + self.flip = preset['flip'] + + # Width in config file should be set to 0 even if not used, + # checking nonetheless + try: + self.width = preset['width'] + except(KeyError): + self.width = 0 + def parse_arguments(self): - parser = ap.ArgumentParser(prog = 'main.py', description = 'Program for processing a 2D image into 3D fingerprint.') + + # Parse arguments + parser = ap.ArgumentParser(prog = 'main.py', description = + 'Program for processing a 2D image into 3D fingerprint.') # positional arguments parser.add_argument("input_file", type = str, help = "Location with input file") parser.add_argument("output_file", type = str, help = "Output file location") parser.add_argument("dpi", type = int, help = "Scanner dpi") + + # predefined width + parser.add_argument('-w', "--width", type= int, help = "Option to input predefined width") + + # boolean switch parser.add_argument('-f', "--flip", help="Flip input image", - type = bool, action = ap.BooleanOptionalAction) # boolean switch + type=bool, action=ap.BooleanOptionalAction) - # file with default presets - parser.add_argument('-pf', "--preset_file", help = "File with presets") + # file with configuration containing presets + parser.add_argument('-c', "--config_file", help = "Config file to save the preset into") + + # new preset name + parser.add_argument('-p', "--preset", help = "Name of the newly created preset") + + # array of unknown length, all filter names saved inside parser.add_argument('filters', type = str, nargs = '*', help = "List of filter names") + self.args = parser.parse_args() - def convert_dpi(self): - height = self.dimensions[0] - width = self.dimensions[1] - self.height = height / self.dpi * 25.4 # conversion to milimeters - self.width = width / self.dpi * 25.4 - self.print_debug([self.height, self.width, self.dimensions[2]]) def filter_factory(self, filter_name): - if filter_name == "average": - return flt.filter_average - elif filter_name == "blur": - return flt.filter_blur - elif filter_name == "gaussian": - return flt.filter_gaussian - elif filter_name == "median": - return flt.filter_median - elif filter_name == "erode": - return flt.filter_erode - elif filter_name == "dilate": - return flt.filter_dilate - elif filter_name == "opening": - return flt.filter_opening - elif filter_name == "closing": - return flt.filter_closing + # selects filter method of filters library + # better this than a 100 if/else + return getattr(flt, filter_name) + + + def convert_dpi(self): + + # conversion from inches to milimeters + self.size = np.empty(2) + self.size[0] = self.img.size[0] # / self.dpi * 25.4 # width + self.size[1] = self.img.size[1] # / self.dpi * 25.4 # height + + + def resize_image(self): + + # open image as python image object + print("Resize image", file = sys.stderr) + + # resize if target width passed as an argument + if self.width: + self.size[0] = int( + self.width * self.img.size[0] / self.img.size[1]) + self.size[1] = self.width + print(self.size) + self.img = self.img.resize( + (np.array(self.size).astype(int))) else: - raise ValueError("Invalid filter name") + self.convert_dpi() + #self.img = self.img.resize((np.array(self.size)).astype(int)) + + #convert to numpy array for further processing + self.img = np.array(self.img) + + + def flip_image(self): - def process_image(self): - # resize img to the new width # flip image when mirroring is needed + # should be used only if we want a positive form + if self.flip: - print("Flipping image") - self.img = cv.flip(self.img, 1) + print("Flipping image", file = sys.stderr) + self.img = cv.flip(self.img, 1) # 1 for vertical flip + def apply_filter(self): - self.process_image() + if len(self.filters) == 0: # save original image filter = flt.filter_none @@ -96,14 +156,20 @@ class apply_filters: filter.apply(self) self.save_image() - def print_debug(self, dimensions): - print("Height: " + str(dimensions[0])) - print("Width: " + str(dimensions[1])) + + def print_size(self, size): + print("Width: " + str(size[0]), file = sys.stderr) + print("Height: " + str(size[1]), file = sys.stderr) + def save_image(self): - ''' Save processed image. ''' + # Save processed image. plt.xticks([]), plt.yticks([]) plt.axis('off') - plt.savefig(self.output_file) + print("Saving image", file = sys.stderr) + + # TODO idk what dpi means, and if it should be put in here + plt.savefig(self.output_file)#, dpi=self.dpi) + app = apply_filters()