|
|
|
@ -8,6 +8,7 @@ import argparse as ap
|
|
|
|
|
import sys
|
|
|
|
|
import json
|
|
|
|
|
from os.path import exists
|
|
|
|
|
import hashlib
|
|
|
|
|
|
|
|
|
|
# Libraries for image processing
|
|
|
|
|
import numpy as np
|
|
|
|
@ -18,7 +19,6 @@ from stl import mesh
|
|
|
|
|
# Import custom image filter library
|
|
|
|
|
import filters as flt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class app:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
# Parse arguments from command line
|
|
|
|
@ -286,7 +286,7 @@ class app:
|
|
|
|
|
|
|
|
|
|
plt.show()
|
|
|
|
|
self.save_stl()
|
|
|
|
|
print(f"Saving model to ", self.stl_path, file=sys.stderr)
|
|
|
|
|
print(f"Saving model to ", self.stl_filename, file=sys.stderr)
|
|
|
|
|
|
|
|
|
|
def prepare_heightmap(self):
|
|
|
|
|
'''Modify image values to get usable height/depth values.
|
|
|
|
@ -327,18 +327,70 @@ class app:
|
|
|
|
|
|
|
|
|
|
self.meshgrid = np.meshgrid(x, y)
|
|
|
|
|
|
|
|
|
|
def write_stl_header(self):
|
|
|
|
|
'''Write stl header.
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
# Truncate if necessary
|
|
|
|
|
if (len(self.param_string) > 80):
|
|
|
|
|
self.param_string = self.param_string[:80]
|
|
|
|
|
print("Warning: Parameter string too long, truncating", file=sys.stderr)
|
|
|
|
|
|
|
|
|
|
# Overwrite stl header (which is only 80 bytes)
|
|
|
|
|
print("Writing info to stl header", file=sys.stderr)
|
|
|
|
|
with open(self.stl_filename, "r+") as f:
|
|
|
|
|
f.write(self.param_string)
|
|
|
|
|
|
|
|
|
|
def get_ID(self):
|
|
|
|
|
'''Get unique ID for the model.
|
|
|
|
|
Consists of pair input_file + preset_name.
|
|
|
|
|
'''Get unique ID for the model, used in filename and on the model backside.
|
|
|
|
|
Also create parameter string for stl header, which is used to create ID using hash function SHA512.
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
# TODO: somehow compress this to fit it onto the model
|
|
|
|
|
self.id = self.input_file.split("/")[-1].split(".")[0] + "_" + self.preset_name
|
|
|
|
|
# TODO: hash is not unique, find a better way
|
|
|
|
|
# TODO: stl file format has 80 chars for header, use that space to store info
|
|
|
|
|
# python generates a random value for security reasons, it has to be turned off
|
|
|
|
|
self.id = str(hash(self.id))
|
|
|
|
|
#print(self.id)
|
|
|
|
|
# these are the same for all types of models
|
|
|
|
|
param_list = [self.input_file, str(self.dpi)]
|
|
|
|
|
|
|
|
|
|
# add parameters specific to the model creation process
|
|
|
|
|
if self.args.config:
|
|
|
|
|
param_list.append(self.config_file)
|
|
|
|
|
param_list.append(self.preset_name)
|
|
|
|
|
else:
|
|
|
|
|
# add filters with their params
|
|
|
|
|
filter_list = []
|
|
|
|
|
for i in range(len(self.filters)):
|
|
|
|
|
tmp_params = []
|
|
|
|
|
for j in self.params[i+1]:
|
|
|
|
|
if self.params[i+1][j] != None:
|
|
|
|
|
tmp_params.append(str(j[:3] + ":" + str(self.params[i+1][j])))
|
|
|
|
|
tmp_params = ",".join(tmp_params)
|
|
|
|
|
tmp = str(self.filters[i][0:3])
|
|
|
|
|
if tmp_params != "":
|
|
|
|
|
tmp = tmp + ";" + str(tmp_params)
|
|
|
|
|
filter_list.append(tmp)
|
|
|
|
|
filter_string = ">".join(filter_list)
|
|
|
|
|
param_list.append(filter_string)
|
|
|
|
|
|
|
|
|
|
# these are the same for all types of models
|
|
|
|
|
param_list.append(str(self.height_line))
|
|
|
|
|
param_list.append(str(self.height_base))
|
|
|
|
|
|
|
|
|
|
# add parameters specific to the model type
|
|
|
|
|
if self.mode == "curved":
|
|
|
|
|
param_list.append(str(self.curv_rate_x))
|
|
|
|
|
param_list.append(str(self.curv_rate_y))
|
|
|
|
|
|
|
|
|
|
if self.mode == "planar":
|
|
|
|
|
param_list.append("P")
|
|
|
|
|
|
|
|
|
|
if self.args.mirror:
|
|
|
|
|
param_list.append("M")
|
|
|
|
|
|
|
|
|
|
# string that will later be put inside the header of an stl file
|
|
|
|
|
self.param_string = "\\".join(param_list) + "\n"
|
|
|
|
|
|
|
|
|
|
# hash the param string to get unique ID, this will be put in filename and on the back of the model
|
|
|
|
|
# not using built-in hash function because it's seed cannot be set to constant number
|
|
|
|
|
# don't need to worry about collisions and security, just need a relatively unique ID
|
|
|
|
|
self.id = str(hashlib.sha512(self.param_string.encode('utf-8')).hexdigest())[:10]
|
|
|
|
|
|
|
|
|
|
def append_faces(self, faces, c):
|
|
|
|
|
# Function to add faces to the list
|
|
|
|
@ -501,7 +553,7 @@ class app:
|
|
|
|
|
count = self.append_faces(faces, count)
|
|
|
|
|
|
|
|
|
|
self.create_stl_mesh(faces, vertices)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_stl_curved(self):
|
|
|
|
|
'''Map fingerprint to finger model.
|
|
|
|
|
'''
|
|
|
|
@ -612,18 +664,10 @@ class app:
|
|
|
|
|
'''Save final mesh to stl file.
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
# TODO: add a hash function to create ID specific to
|
|
|
|
|
# input image + preset from config. file or from console + input params
|
|
|
|
|
# TODO: add the full parameters and filters to a file inside output dir.
|
|
|
|
|
# TODO: somehow add the full params to the stl file header if possible.
|
|
|
|
|
# TODO: add the ID to backplate
|
|
|
|
|
# TODO: add the ID to stl file name
|
|
|
|
|
|
|
|
|
|
# for now only path + id(input filename + preset name) + .stl is used
|
|
|
|
|
# TODO: add output filename to the filename, hash the ID
|
|
|
|
|
# stl_filename = self.stl_path.rsplit("/")[0] + self.output_file.split("/"))[-1] + "_" + self.id + ".stl"
|
|
|
|
|
stl_filename = self.output_file.split(".")[0] + "_" + self.id + ".stl"
|
|
|
|
|
self.stl_model.save(stl_filename)
|
|
|
|
|
# create output file name, save it and write header with file info
|
|
|
|
|
self.stl_filename = self.output_file.split(".")[0] + "_" + self.id + ".stl"
|
|
|
|
|
self.stl_model.save(self.stl_filename)
|
|
|
|
|
self.write_stl_header()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# run the application
|
|
|
|
|