Reworked logging, split it to separate file, refactored and cleaned main and filters files code, fixed test.sh overwriting originals

master
Rostislav Lán 2 years ago
parent 71d23f9cdb
commit 13fc747d63

@ -64,7 +64,7 @@ Once all the requirements are installed, the program is ready to use. There are
1. manually list filter names and parameters from command line 1. manually list filter names and parameters from command line
```sh ```sh
python3 src/main.py res/examples/Palec_P4.tif res/examples/Palec_P4_from_shell.png 600 total_variation weight=0.15 median ksize=5 python3 src/main.py res/examples/Palec_P4.tif res/examples/Palec_P4_from_cline.png 600 total_variation weight=0.15 median ksize=5
``` ```
2. from preset saved in a json config file, that can be used to tune and modify existing presetrs, or create new ones 2. from preset saved in a json config file, that can be used to tune and modify existing presetrs, or create new ones
@ -75,6 +75,8 @@ Once all the requirements are installed, the program is ready to use. There are
# Configuration and presets # Configuration and presets
There is an option to input the filter series as a preset from json configuration file. There is an option to input the filter series as a preset from json configuration file.
This preset is automatically stored inside a json file, which serves as a database for storing filters.
This prevents losing filter preset information when modifying filter which was used to generate 3D models.
<table style="width:100%;"> <table style="width:100%;">
<thead> <thead>
@ -127,7 +129,17 @@ There is an option to input the filter series as a preset from json configuratio
</tbody> </tbody>
</table> </table>
There is also an option to save current command line setting as a preset using -d switch:
* General command for saving filter preset
```sh
python3 src/main.py input_file output_file dpi -d new_preset_name filters
```
* Working example
```sh
python3 src/main.py res/examples/Palec_P4.tif res/examples/Palec_P4_from_cline.png 600 -d preset_gaussian gaussian sigma=1
```
All the filters used and their parameters are described below. All the filters used and their parameters are described below.

@ -6,7 +6,7 @@
from os.path import exists from os.path import exists
import json import json
import hashlib import hashlib
import log
def save_preset(filters, params, preset_name): def save_preset(filters, params, preset_name):
'''Save filter preset to database. '''Save filter preset to database.
@ -46,7 +46,7 @@ def store_to_db(preset, preset_name):
# If database doesn't exist, create it # If database doesn't exist, create it
if not exists("db.json"): if not exists("db.json"):
print("Storing preset to database") log.print_message("Storing preset to database")
with open("db.json", 'w') as db: with open("db.json", 'w') as db:
json.dump(preset, db) json.dump(preset, db)
else: else:
@ -61,9 +61,9 @@ def store_to_db(preset, preset_name):
# If preset already exists, skip it # If preset already exists, skip it
if preset_name in db_presets: if preset_name in db_presets:
print("Preset already exists in database, skipping") log.print_message("Preset already exists in database, skipping")
else: else:
print("Storing preset to database") log.print_message("Storing preset to database")
db_presets.update(preset) db_presets.update(preset)
# Finally write the updated entries to db file # Finally write the updated entries to db file
@ -91,10 +91,10 @@ def parse_conf(preset_name, filters, params, config_file):
if attribute != "name": if attribute != "name":
params[i][attribute] = value params[i][attribute] = value
parse_params(params[i]) parse_params(params[i])
print("Loaded preset: " + preset_name + log.print_message("Loaded preset:", preset_name,
" from file: " + config_file) "from file:", config_file)
else: else:
print("Preset not found") log.print_message("Preset not found")
def parse_params(params): def parse_params(params):

@ -41,7 +41,6 @@ class gaussian(filter):
# Standard deviation for Gaussian kernel # Standard deviation for Gaussian kernel
sigma = float(params["sigma"]) if params["sigma"] else 1 sigma = float(params["sigma"]) if params["sigma"] else 1
print("with params: sigma: " + str(sigma))
self.img = skiflt.gaussian( self.img = skiflt.gaussian(
self.img, sigma=sigma, preserve_range=True) self.img, sigma=sigma, preserve_range=True)
@ -59,7 +58,6 @@ class median(filter):
# Used kernel is disk of size ksize # Used kernel is disk of size ksize
ksize = int(params["ksize"]) if params["ksize"] else 3 ksize = int(params["ksize"]) if params["ksize"] else 3
print("with params: ksize: " + str(ksize))
self.img = skiflt.median(self.img, footprint=skimorph.disk(ksize)) self.img = skiflt.median(self.img, footprint=skimorph.disk(ksize))
@ -84,8 +82,6 @@ class bilateral(filter):
# A larger value results in averaging of pixels with larger spatial differences # A larger value results in averaging of pixels with larger spatial differences
sigmaSpace = int(params["sigmaSpace"]) if params["sigmaSpace"] else 75 sigmaSpace = int(params["sigmaSpace"]) if params["sigmaSpace"] else 75
print("with params: diameter: " + str(diameter) + " sigmaColor: " +
str(sigmaColor) + " sigmaSpace: " + str(sigmaSpace))
self.img = np.uint8(self.img) self.img = np.uint8(self.img)
self.img = cv.bilateralFilter( self.img = cv.bilateralFilter(
self.img, diameter, sigmaColor, sigmaSpace) self.img, diameter, sigmaColor, sigmaSpace)
@ -115,8 +111,6 @@ class bilateral_scikit(filter):
sigmaSpace = float(params["sigmaSpace"] sigmaSpace = float(params["sigmaSpace"]
) if params["sigmaSpace"] else 9.0 ) if params["sigmaSpace"] else 9.0
print("with params: sigma_color: " + str(sigmaColor) +
" sigma_spatial: " + str(sigmaSpace))
self.img = skirest.denoise_bilateral( self.img = skirest.denoise_bilateral(
self.img, sigma_color=sigmaColor, sigma_spatial=sigmaSpace) self.img, sigma_color=sigmaColor, sigma_spatial=sigmaSpace)
self.img = np.uint8(self.img * 255.0) # converting back to uint8 self.img = np.uint8(self.img * 255.0) # converting back to uint8
@ -144,8 +138,6 @@ class nlmeans(filter):
# Cut-off distance, higher means more smoothed image # Cut-off distance, higher means more smoothed image
h = float(params["h"])*sigma if params["h"] else 0.1*sigma h = float(params["h"])*sigma if params["h"] else 0.1*sigma
print("with params: patch_size: " + str(patch_size) + " patch_distance: " +
str(patch_distance) + " h: " + str(round(h, 4)))
self.img = skirest.denoise_nl_means( self.img = skirest.denoise_nl_means(
self.img, patch_size=patch_size, fast_mode=True, patch_distance=patch_distance, h=h) self.img, patch_size=patch_size, fast_mode=True, patch_distance=patch_distance, h=h)
self.img = np.uint8(self.img * 255.0) # converting back to uint8 self.img = np.uint8(self.img * 255.0) # converting back to uint8
@ -166,7 +158,6 @@ class total_variation(filter):
# Denoising weight. Larger values result in more denoising. # Denoising weight. Larger values result in more denoising.
weight = float(params["weight"]) if params["weight"] else 0.1 weight = float(params["weight"]) if params["weight"] else 0.1
print("with params: weight: " + str(weight))
self.img = skirest.denoise_tv_chambolle( self.img = skirest.denoise_tv_chambolle(
self.img, weight=weight) self.img, weight=weight)
self.img = np.uint8(self.img * 255.0) # converting back to uint8 self.img = np.uint8(self.img * 255.0) # converting back to uint8
@ -184,7 +175,6 @@ class block_match(filter):
def apply(self, params): def apply(self, params):
sigma = float(params["sigma"]) if params["sigma"] else 20 sigma = float(params["sigma"]) if params["sigma"] else 20
print("with params: sigma: " + str(sigma))
self.img = bm3d.bm3d(self.img, sigma_psd=sigma, self.img = bm3d.bm3d(self.img, sigma_psd=sigma,
stage_arg=bm3d.BM3DStages.ALL_STAGES) stage_arg=bm3d.BM3DStages.ALL_STAGES)
@ -207,8 +197,6 @@ class unsharp_mask_scikit(filter):
# strength of the unsharp mask # strength of the unsharp mask
amount = float(params["amount"]) if params["amount"] else 1.0 amount = float(params["amount"]) if params["amount"] else 1.0
print("with params: radius: " +
str(radius) + " amount: " + str(amount))
self.img = skiflt.unsharp_mask(self.img, radius=radius, self.img = skiflt.unsharp_mask(self.img, radius=radius,
amount=amount, channel_axis=None) amount=amount, channel_axis=None)
self.img = np.uint8(self.img * 255.0) # converting back to uint self.img = np.uint8(self.img * 255.0) # converting back to uint
@ -315,8 +303,6 @@ class binarize(filter):
maxval = int(params["maxval"]) if params["maxval"] else 255 maxval = int(params["maxval"]) if params["maxval"] else 255
type = int(params["type"]) if params["type"] else 0 type = int(params["type"]) if params["type"] else 0
print("with params: threshold: " + str(threshold) +
" maxval: " + str(maxval) + " type: " + str(type))
self.img = cv.threshold(self.img, threshold, maxval, type)[1] self.img = cv.threshold(self.img, threshold, maxval, type)[1]
@ -338,8 +324,6 @@ class add_margin(filter):
margin = int(params["margin"]) if params["margin"] else 10 margin = int(params["margin"]) if params["margin"] else 10
color = int(params["color"]) if params["color"] else 255 color = int(params["color"]) if params["color"] else 255
print("with params: margin: " + str(margin) + " color: " + str(color))
self.fig.set_size_inches( self.fig.set_size_inches(
((self.width + 2 * margin) / self.dpi, (self.height + 2 * margin) / self.dpi)) ((self.width + 2 * margin) / self.dpi, (self.height + 2 * margin) / self.dpi))
self.img = cv.copyMakeBorder( self.img = cv.copyMakeBorder(
@ -365,7 +349,6 @@ class convolve(filter):
kernel = np.array(params["kernel"]) if params["kernel"] else np.ones( kernel = np.array(params["kernel"]) if params["kernel"] else np.ones(
(3, 3), np.float32) / 9 (3, 3), np.float32) / 9
print("with params: kernel: \n" + str(kernel))
self.img = cv.filter2D(self.img, -1, kernel) self.img = cv.filter2D(self.img, -1, kernel)
@ -380,7 +363,6 @@ class blur(filter):
def apply(self, params): def apply(self, params):
ksize = int(params["ksize"]) if params["ksize"] else 3 ksize = int(params["ksize"]) if params["ksize"] else 3
print("with params: ksize: " + str(ksize))
self.img = cv.blur(self.img, ksize=(ksize, ksize)) self.img = cv.blur(self.img, ksize=(ksize, ksize))
@ -395,8 +377,6 @@ class denoise(filter):
sWS = int(params["searchWindowSize"] sWS = int(params["searchWindowSize"]
) if params["searchWindowSize"] else 21 ) if params["searchWindowSize"] else 21
# print("with params: h: " + str(h) +
# " tWS: " + str(tWS) + " sWS: " + str(sWS))
self.img = np.uint8(self.img) self.img = np.uint8(self.img)
self.img = cv.fastNlMeansDenoising( self.img = cv.fastNlMeansDenoising(
self.img, h, tWS, sWS) self.img, h, tWS, sWS)
@ -413,7 +393,6 @@ class sharpen(filter):
kernel = np.matrix(params["kernel"]) if params["kernel"] else np.array( kernel = np.matrix(params["kernel"]) if params["kernel"] else np.array(
[[0, -1, 0], [-1, 5, -1], [0, -1, 0]]) [[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
# print("with params: kernel: \n" + str(kernel))
self.img = cv.filter2D(self.img, ddepth=-1, kernel=kernel) self.img = cv.filter2D(self.img, ddepth=-1, kernel=kernel)
@ -434,8 +413,6 @@ class unsharp_mask(filter):
blurred = cv.medianBlur(self.img, ksize) blurred = cv.medianBlur(self.img, ksize)
lap = cv.Laplacian(blurred, cv.CV_32F) lap = cv.Laplacian(blurred, cv.CV_32F)
# print("with params: strength: " +
# str(strength) + " ksize: " + str(ksize))
self.img = blurred - strength*lap self.img = blurred - strength*lap
@ -458,8 +435,6 @@ class unsharp_mask_pil(filter):
# Threshold controls the minimum brightness change that will be sharpened # Threshold controls the minimum brightness change that will be sharpened
threshold = int(params["threshold"]) if params["threshold"] else 3 threshold = int(params["threshold"]) if params["threshold"] else 3
# print("with params: radius: " +
# str(radius) + " percent: " + str(percent) + " threshold: " + str(threshold))
self.img = np.uint8(self.img) self.img = np.uint8(self.img)
tmp = Image.fromarray(self.img) tmp = Image.fromarray(self.img)
tmp = tmp.filter(ImageFilter.UnsharpMask(radius, percent, threshold)) tmp = tmp.filter(ImageFilter.UnsharpMask(radius, percent, threshold))
@ -481,7 +456,6 @@ class erode(filter):
kernel = np.matrix(params["kernel"]) if params["kernel"] else cv.getStructuringElement( kernel = np.matrix(params["kernel"]) if params["kernel"] else cv.getStructuringElement(
cv.MORPH_ELLIPSE, (3, 3)) cv.MORPH_ELLIPSE, (3, 3))
print("with params: kernel: \n" + str(kernel))
self.img = cv.morphologyEx( self.img = cv.morphologyEx(
np.uint8(self.img), op=cv.MORPH_ERODE, kernel=kernel) np.uint8(self.img), op=cv.MORPH_ERODE, kernel=kernel)
@ -501,7 +475,6 @@ class dilate(filter):
kernel = np.matrix(params["kernel"]) if params["kernel"] else cv.getStructuringElement( kernel = np.matrix(params["kernel"]) if params["kernel"] else cv.getStructuringElement(
cv.MORPH_ELLIPSE, (3, 3)) cv.MORPH_ELLIPSE, (3, 3))
print("with params: kernel: \n" + str(kernel))
self.img = cv.morphologyEx( self.img = cv.morphologyEx(
np.uint8(self.img), op=cv.MORPH_DILATE, kernel=kernel) np.uint8(self.img), op=cv.MORPH_DILATE, kernel=kernel)

@ -0,0 +1,22 @@
"""! @file log.py
@brief File with printing functions
@author xlanro00
"""
import sys
def print_message(*args, **kwargs):
'''Print given message to stderr.
:param message: message to be printed
'''
print("APP:", *args, file=sys.stderr, **kwargs)
def error_exit(error_message):
'''Print given error message and exit the application.
:param message: error message to be printed
'''
print("ERROR:" + error_message, file=sys.stderr)
exit(1)

@ -5,8 +5,6 @@
# Import basic libraries # Import basic libraries
import argparse as ap import argparse as ap
import sys
import json
from os.path import exists from os.path import exists
import hashlib import hashlib
import math import math
@ -22,6 +20,7 @@ import trimesh.transformations as tmtra
# Import custom image filter library # Import custom image filter library
import filters as flt import filters as flt
import config_parser as cp import config_parser as cp
import log
class app: class app:
'''Main class for the application. '''Main class for the application.
@ -41,28 +40,30 @@ class app:
cp.parse_conf(self.preset_name, self.filters, self.params, self.config_file) cp.parse_conf(self.preset_name, self.filters, self.params, self.config_file)
elif self.args.filters: elif self.args.filters:
print("No config file given, using command line arguments") filter_index = 0
i = 0 log.print_message(
"No config file given, using command line arguments")
# Otherwise expect filters from command line # Otherwise expect filters from command line
for filter_part in self.args.filters: for filter_part in self.args.filters:
# If no '=' char in filter, it is a new filter name # If no '=' char in filter, it is a new filter name
if filter_part.find('=') == -1: if filter_part.find('=') == -1:
self.filters.append(filter_part) self.filters.append(filter_part)
i += 1 filter_index += 1
self.params[i] = {} # create empty dict for params # create empty dict for params
self.params[filter_index] = {}
# Otherwise it's a parameter for current filter # Otherwise it's a parameter for current filter
else: else:
key, value = filter_part.split('=') key, value = filter_part.split('=')
self.params[i][key] = value self.params[filter_index][key] = value
cp.parse_params(self.params[i]) cp.parse_params(self.params[filter_index])
# If database flag is set, save filters to database as a new preset # If database flag is set, save filters to database as a new preset
if self.args.database: if self.args.database:
cp.save_preset(self.filters, self.params, self.args.database[0]) cp.save_preset(self.filters, self.params, self.args.database[0])
else: else:
print("No filters given, saving original image") log.print_message("No filters given, saving original image")
# Set input and output file paths, dpi and mirror flag for easier readability # Set input and output file paths, dpi and mirror flag for easier readability
self.input_file = self.args.input_file self.input_file = self.args.input_file
@ -72,9 +73,8 @@ class app:
if exists(self.input_file): if exists(self.input_file):
self.run_filtering() self.run_filtering()
else: else:
self.error_exit("Input file " + self.input_file + log.error_exit("Input file " + self.input_file +
" does not exist") " does not exist")
if self.args.stl: if self.args.stl:
@ -128,12 +128,12 @@ class app:
if len(self.args.stl) < 3: if len(self.args.stl) < 3:
self.height_line = 2 self.height_line = 2
self.height_base = 10 self.height_base = 10
print( log.print_message(
"Warning: Too few arguments, using default values (10mm base, 2mm lines)") "Warning: Too few arguments, using default values (10mm base, 2mm lines)")
else: else:
self.height_line = float(self.args.stl[1]) self.height_line = float(self.args.stl[1])
self.height_base = float(self.args.stl[2]) self.height_base = float(self.args.stl[2])
print("Base height:", self.height_base, log.print_message("Base height:", self.height_base,
"mm, lines depth/height:", self.height_line, "mm") "mm, lines depth/height:", self.height_line, "mm")
elif self.args.stl[0] == 'c': elif self.args.stl[0] == 'c':
@ -145,40 +145,31 @@ class app:
self.height_base = 10 self.height_base = 10
self.curv_rate_x = 2 self.curv_rate_x = 2
self.curv_rate_y = 6 self.curv_rate_y = 6
print( log.print_message("Warning: Too few arguments, using default values (2mm lines, curvature 0.5 on x, 0.5 on y)")
"Warning: Too few arguments, using default values (2mm lines, curvature 0.5 on x, 0.5 on y)")
else: else:
self.height_line = float(self.args.stl[1]) self.height_line = float(self.args.stl[1])
self.height_base = float(self.args.stl[2]) self.height_base = float(self.args.stl[2])
self.curv_rate_x = float(self.args.stl[3]) self.curv_rate_x = float(self.args.stl[3])
self.curv_rate_y = float(self.args.stl[4]) self.curv_rate_y = float(self.args.stl[4])
print("Line height:", self.height_line, "mm, base height: ", self.height_base, log.print_message("Line height:", self.height_line, "mm, base height:", self.height_base,
"mm, x axis curvature: ", self.curv_rate_x, ", y axis curvature:", self.curv_rate_y) "mm, x axis curvature:", self.curv_rate_x, ", y axis curvature:", self.curv_rate_y)
elif self.args.stl[0] == 'm': elif self.args.stl[0] == 'm':
self.mode = "mapped" self.mode = "mapped"
# TODO: add default values for mapped mode, add finger model? # TODO: add default values for mapped mode, add finger model?
if len(self.args.stl) < 2: if len(self.args.stl) < 2:
print( log.print_message(
"Warning: Too few arguments, using default values") "Warning: Too few arguments, using default values")
else: else:
self.height_line = float(self.args.stl[1]) self.height_line = float(self.args.stl[1])
self.finger_model = self.args.stl[2] self.finger_model = self.args.stl[2]
else: else:
self.error_exit("Unrecognized generation mode") log.error_exit("Unrecognized generation mode")
print("Stl generation in ", self.mode) log.print_message("Stl generation in", self.mode, "mode")
self.run_stl() self.run_stl()
def error_exit(self, message):
'''Print given error message and exit the application.
:param message: error message to be printed
'''
print("ERROR:", message, file=sys.stderr)
exit(1)
# ------------------------- FILTERING -------------------------# # ------------------------- FILTERING -------------------------#
def run_filtering(self): def run_filtering(self):
@ -216,7 +207,7 @@ class app:
'''Mirror image using opencv, should be used if we want a positive model. '''Mirror image using opencv, should be used if we want a positive model.
''' '''
print("Mirroring image", file=sys.stderr) log.print_message("Mirroring image")
self.img = cv.flip(self.img, 1) # 1 for vertical mirror self.img = cv.flip(self.img, 1) # 1 for vertical mirror
def apply_filters(self): def apply_filters(self):
@ -228,7 +219,12 @@ class app:
for i, filter_name in enumerate(self.filters): for i, filter_name in enumerate(self.filters):
# Get filter class from filter.py, use the apply method # Get filter class from filter.py, use the apply method
filter = getattr(flt, filter_name) filter = getattr(flt, filter_name)
print("Applying filter:", filter_name, file=sys.stderr) log.print_message("Applying filter:", filter_name)
for param in self.params[i+1]:
if self.params[i+1][param] is not None:
log.print_message("\twith parameter", param,
"=", str(self.params[i+1][param]))
filter.apply(self, self.params[i+1]) filter.apply(self, self.params[i+1])
else: else:
pass pass
@ -237,7 +233,7 @@ class app:
'''Save processed image to the output file. '''Save processed image to the output file.
''' '''
print("Saving image to", self.output_file, file=sys.stderr) log.print_message("Saving image to", self.output_file)
# Colormap must be set to grayscale to avoid color mismatch. # Colormap must be set to grayscale to avoid color mismatch.
ax.imshow(self.img, cmap="gray") ax.imshow(self.img, cmap="gray")
@ -253,7 +249,7 @@ class app:
# create ID for the model from all its parameters # create ID for the model from all its parameters
self.get_ID() self.get_ID()
print("Creating mesh", file=sys.stderr) log.print_message("Creating mesh")
# Create a mesh using one of two modes # Create a mesh using one of two modes
if self.mode == "planar": if self.mode == "planar":
@ -267,11 +263,11 @@ class app:
self.make_stl_map() self.make_stl_map()
else: else:
self.error_exit("Mode not supported") log.error_exit("Incorrect stl generation mode")
plt.show() plt.show()
self.save_stl() self.save_stl()
print(f"Saving model to ", self.stl_filename, file=sys.stderr) log.print_message("Saving model to", self.stl_filename)
def prepare_heightmap(self): def prepare_heightmap(self):
'''Scale image values to get values from 0 to 255. '''Scale image values to get values from 0 to 255.
@ -281,27 +277,27 @@ class app:
''' '''
if self.img.dtype != np.uint8: if self.img.dtype != np.uint8:
print("Converting to uint8", file=sys.stderr) log.print_message("Converting to uint8")
self.img = self.img / np.max(self.img) * 255 self.img = self.img / np.max(self.img) * 255
self.img = self.img.astype(np.uint8) self.img = self.img.astype(np.uint8)
if self.mode == "planar": if self.mode == "planar":
if self.height_base <= 0: if self.height_base <= 0:
self.error_exit("Depth of plate height must be positive") log.error_exit("Depth of plate height must be positive")
if self.height_line + self.height_base <= 0: if self.height_line + self.height_base <= 0:
self.error_exit("Line depth must be less than plate thickness") log.error_exit("Line depth must be less than plate thickness")
if self.mode == "curved": if self.mode == "curved":
# Don't need to check curvature, check only heights # Don't need to check curvature, check only heights
if self.height_base <= 0 or self.height_line <= 0: if self.height_base <= 0 or self.height_line <= 0:
self.error_exit("Base and line height must both be positive") log.error_exit("Base and line height must both be positive")
if self.mode == "mapped": if self.mode == "mapped":
if self.height_line <= 0: if self.height_line <= 0:
self.error_exit("Line height must be positive") log.error_exit("Line height must be positive")
if not exists(self.finger_model): if not exists(self.finger_model):
self.error_exit("Finger model file does not exist") log.error_exit("Finger model file does not exist")
self.height_base = 0 self.height_base = 0
# TODO: curved height base could be done here? # TODO: curved height base could be done here?
@ -324,10 +320,10 @@ class app:
# Truncate if necessary # Truncate if necessary
if (len(self.param_string) >= 80): if (len(self.param_string) >= 80):
self.param_string = self.param_string[:80] self.param_string = self.param_string[:80]
print("Warning: Parameter string too long, truncating", file=sys.stderr) log.print_message("Warning: Parameter string too long, truncating")
# Overwrite stl header (which is only 80 bytes) # Overwrite stl header (which is only 80 bytes)
print("Writing info to stl header", file=sys.stderr) log.print_message("Writing info to stl header")
with open(self.stl_filename, "r+") as f: with open(self.stl_filename, "r+") as f:
f.write(self.param_string) f.write(self.param_string)
@ -681,8 +677,7 @@ class app:
# TODO: maybe use trimesh.update_vertices # TODO: maybe use trimesh.update_vertices
log.print_message("Mapping to finger")
print("Mapping to finger")
# TODO: try to merge meshes? or stl files? # TODO: try to merge meshes? or stl files?
# trimesh library? # trimesh library?
finger = trimesh.load(self.finger_model) finger = trimesh.load(self.finger_model)
@ -715,7 +710,6 @@ class app:
self.stl_model = trimesh.util.concatenate([finger, fingerprint]) self.stl_model = trimesh.util.concatenate([finger, fingerprint])
def save_stl(self): def save_stl(self):
'''Save final mesh to stl file. '''Save final mesh to stl file.
''' '''

@ -9,15 +9,15 @@ source .venv/bin/activate
#----------------------------Configuration------------------------------# #----------------------------Configuration------------------------------#
# place all image files to one folder # place all image files to one folder
input_path=res/test/test-skript input_path=res/test/Jenetrics/leva
# !!!!!!!!!!!!!!!!!! # !!!!!!!!!!!!!!!!!!
# this is very important, run this on directories containing files with the same dpi # this is very important, run this on directories containing files with the same dpi
dpi=500 dpi=600
# !!!!!!!!!!!!!!!!!! # !!!!!!!!!!!!!!!!!!
# recommend png, it's supported by opencv # recommend png, it's supported by opencv
format=jpg format=png
# name of configuration file # name of configuration file
config_file=conf/conf.json config_file=conf/conf.json
@ -28,16 +28,18 @@ presets=("ridge")
# generate stl files and set generation mode {"planar", "curved", "mapped"} # generate stl files and set generation mode {"planar", "curved", "mapped"}
generate_stl=true generate_stl=true
generate_stl_mode="planar" generate_stl_mode="curved"
# in 1/10 of milimeters # in 1/10 of milimeters
height_line=2 height_line=2.5
height_base=3 height_base=6
curv_x=1.5 curv_x=1.3
curv_y=4 curv_y=3
#----------------------------Application---------------------------# #----------------------------Application---------------------------#
# TODO: check if file will overwrite the original, print warning if that's the case
# function to apply filter to all files in directory # function to apply filter to all files in directory
apply_filter() { apply_filter() {
for in in ${file_arr[@]} for in in ${file_arr[@]}
@ -46,14 +48,19 @@ apply_filter() {
[[ -f "$in" ]] || continue [[ -f "$in" ]] || continue
# skip stl files and files with preset name in them # skip stl files and files with preset name in them
[[ "$in" == *_* ]] && continue [[ "$in" == *"ridge"* ]] && continue
[[ "$in" == *".stl" ]] && continue [[ "$in" == *".stl" ]] && continue
((i++)) ((i++))
echo -e "|\n|----------------------- File no. $i: $in ------------------------------|\n" echo -e "\n|----------------------- File no. $i: $in ------------------------------|\n"
if $generate_stl; then if $generate_stl; then
out="${in%%${match1}*}${match1}$format" out="${in%%${match1}*}${match1}$format"
if [[ "$in" == "$out" ]]; then
echo "SCRIPT: Changing filename to avoid overwrite"
out="${in%%${match1}*}_mod${match1}$format"
fi
case "$generate_stl_mode" in case "$generate_stl_mode" in
"planar") "planar")
python3 $exec_path $in $out $dpi -c $config_file $1 --stl p $height_line $height_base || break python3 $exec_path $in $out $dpi -c $config_file $1 --stl p $height_line $height_base || break
@ -65,7 +72,7 @@ apply_filter() {
python3 $exec_path $in $out $dpi -c $config_file $1 --stl m $height_line $height_base $fp_file|| break python3 $exec_path $in $out $dpi -c $config_file $1 --stl m $height_line $height_base $fp_file|| break
;; ;;
*) *)
echo "Invalid stl generation mode" echo "SCRIPT: Invalid stl generation mode"
exit 1 exit 1
;; ;;
esac esac
@ -93,11 +100,11 @@ done
# apply all given filter presets to all the discovered files # apply all given filter presets to all the discovered files
for preset in ${presets[@]} for preset in ${presets[@]}
do do
echo -e "\n|----------------------- Filter "$preset" ------------------------------|\n|" echo -e "\n|----------------------- Filter "$preset" ------------------------------|\n"
j=0 j=0
apply_filter $preset $j apply_filter $preset $j
done done
echo -e "\n|--------------------------- Done ----------------------------------|\n" echo -e "\n|--------------------------- Done ----------------------------------|\n"
echo "Skipped $j files" echo "SCRIPT: Skipped $j files"
echo "Generated $i files" echo "SCRIPT: Generated $i files"

Loading…
Cancel
Save