Fixed dpi scaling issues, added depth setting fot lithophane.

master
Rostislav Lán 2 years ago
parent cc49026636
commit cc166cb5c0

@ -21,14 +21,13 @@ from stl import mesh
import filters as flt import filters as flt
class apply_filters: class app:
def __init__(self): def __init__(self):
# Parse arguments from command line # Parse arguments from command line
self.parse_arguments() self.parse_arguments()
self.params = {} self.params = {}
self.filters = [] self.filters = []
# Parse configuration from json file # Parse configuration from json file
if self.args.config: if self.args.config:
self.config_file = self.args.config[0] self.config_file = self.args.config[0]
@ -56,6 +55,11 @@ class apply_filters:
self.params[i][key] = value self.params[i][key] = value
self.parse_params(self.params[i]) self.parse_params(self.params[i])
if self.args.stl_file:
self.stl_file = self.args.stl_file[0]
self.depth_total = float(self.args.stl_file[1])
self.depth_line = float(self.args.stl_file[2])
self.input_file = self.args.input_file self.input_file = self.args.input_file
self.output_file = self.args.output_file self.output_file = self.args.output_file
self.dpi = self.args.dpi self.dpi = self.args.dpi
@ -133,7 +137,7 @@ class apply_filters:
parser = ap.ArgumentParser(prog='main.py', parser = ap.ArgumentParser(prog='main.py',
description='Program for processing a 2D image into 3D fingerprint.', description='Program for processing a 2D image into 3D fingerprint.',
usage='%(prog)s [-h] [-m | --mirror | --no-mirror] input_file output_file dpi \ usage='%(prog)s [-h] [-m | --mirror | --no-mirror] input_file output_file dpi \
([-c config_file preset | --config config_file preset] | [filters ...]) [-s stl_file | --stl_file stl_file]') ([-c config_file preset | --config config_file preset] | [filters ...]) [-s stl_file | --stl_file stl_file depth_total depth_line]')
# positional arguments # positional arguments
parser.add_argument("input_file", type=str, parser.add_argument("input_file", type=str,
@ -147,11 +151,12 @@ class apply_filters:
type=bool, action=ap.BooleanOptionalAction) type=bool, action=ap.BooleanOptionalAction)
# another boolean switch argument, this time with value, name of the new file # another boolean switch argument, this time with value, name of the new file
parser.add_argument('-s', '--stl_file', type=str, nargs='?', help="make stl model from processed image", required=False) parser.add_argument('-s', '--stl_file', type=str, nargs=3,
help="make stl model from processed image", required=False)
# file with configuration containing presets, new preset name # file with configuration containing presets, new preset name
# pair argument - give both or none # pair argument - give both or none
parser.add_argument('-c', '--config', nargs=2, metavar=('config_file', 'preset'), parser.add_argument('-c', '--config', nargs=2,
help='pair: name of the config file with presets, name of the preset') help='pair: name of the config file with presets, name of the preset')
# array of unknown length, all filter names saved inside # array of unknown length, all filter names saved inside
@ -172,7 +177,6 @@ class apply_filters:
should be used only if we want a positive model should be used only if we want a positive model
''' '''
# TODO make this automatic for positive STL
print("Mirroring image", file=sys.stderr) print("Mirroring image", file=sys.stderr)
self.img = cv.flip(self.img, 1) # 1 for vertical mirror self.img = cv.flip(self.img, 1) # 1 for vertical mirror
@ -211,10 +215,12 @@ class apply_filters:
print("Making meshgrid", file=sys.stderr) print("Making meshgrid", file=sys.stderr)
self.make_meshgrid() self.make_meshgrid()
print("Converting to stl format", file=sys.stderr) print("Converting to stl format", file=sys.stderr)
self.make_mesh() self.make_stl_planar()
#print("Mapping to 3D finger", file=sys.stderr)
#self.map_image_to_3d()
plt.show() plt.show()
print(f"Saving lithophane to ", self.args.stl_file, file=sys.stderr) print(f"Saving lithophane to ", self.stl_file, file=sys.stderr)
self.save_mesh() self.save_stl()
def make_meshgrid(self): def make_meshgrid(self):
''' Create numpy meshgrid. ''' Create numpy meshgrid.
@ -227,27 +233,23 @@ class apply_filters:
self.img = self.img * 255 self.img = self.img * 255
self.img = self.img.astype(np.uint8) self.img = self.img.astype(np.uint8)
# Make depth map from image print("Total depth:", self.depth_total, "mm, line depth/height:", self.depth_line, "mm")
# TODO make this depth/height a param depth_base = self.depth_total - self.depth_line
self.img = (0.5 + (1 - self.img/255)/6) * \
255 / 10 # for positive forms ?
if self.mirror is True:
self.img = (1 - (1 - self.img/255)/6) * \
255 / 10 # for negative forms
# Add zero padding to image # Make depth map from image
self.height = self.img.shape[0] if self.depth_line < 0:
self.width = self.img.shape[1] self.img = (depth_base + (1 - self.img/255) * self.depth_line)
self.print_size(self.img.shape) else:
self.img = (depth_base + (1 - self.img/255) * self.depth_line)
# Create meshgrid for 3D model # Create meshgrid for 3D model
# This sets the scale of stl model # This sets the scale of stl model and number of subdivisions / triangles
# TODO this is an absolutely random constant that fits the scale... x = np.linspace(0, self.width * 25.4 / self.dpi, self.width)
x = np.linspace(0, self.width / 23.6715, self.width) y = np.linspace(0, self.height * 25.4 / self.dpi, self.height)
y = np.linspace(0, self.height / 23.6715, self.height)
self.meshgrid = np.meshgrid(x, y) self.meshgrid = np.meshgrid(x, y)
def make_mesh(self): def make_stl_planar(self):
''' Create mesh from image. ''' Create mesh from image.
Create vertices from meshgrid, add depth values from image. Create vertices from meshgrid, add depth values from image.
Create faces from vertices. Add veectors to the model. Create faces from vertices. Add veectors to the model.
@ -283,7 +285,6 @@ class apply_filters:
faces.append([c + 1, c + 3, c + 2]) faces.append([c + 1, c + 3, c + 2])
return c + 4 return c + 4
# TODO: this can be done more efficiently
# Iterate over all vertices, create faces # Iterate over all vertices, create faces
for i in range(self.height - 1): for i in range(self.height - 1):
for j in range(self.width - 1): for j in range(self.width - 1):
@ -296,7 +297,6 @@ class apply_filters:
count = add_faces(count) count = add_faces(count)
# Add faces for the backside of the lithophane # Add faces for the backside of the lithophane
# TODO: this doesn't work, creates naked edges
null_arr = np.copy(vertex_arr) null_arr = np.copy(vertex_arr)
for i in range(self.height): for i in range(self.height):
for j in range(self.width): for j in range(self.width):
@ -359,11 +359,33 @@ class apply_filters:
for j in range(3): for j in range(3):
self.stl_mesh.vectors[i][j] = vertices[face[j], :] self.stl_mesh.vectors[i][j] = vertices[face[j], :]
def save_mesh(self): def save_stl(self):
''' Save final mesh to stl file. ''' Save final mesh to stl file.
''' '''
self.stl_mesh.save(self.args.stl_file) self.stl_mesh.save(self.stl_file)
def map_image_to_3d(self):
''' Map fingerprint to finger model.
'''
image = apply_filters() x = np.linspace(0, 25.4, self.dpi)
y = np.linspace(0, 25.4, self.dpi)
z1 = np.linspace(0, 10, self.dpi)
z2 = np.linspace(10, 0, self.dpi)
z = np.concatenate((z1, z2))
tmp = np.meshgrid(x, y)
self.mesh_finger = np.meshgrid(tmp,z)
print(len(self.mesh_finger))
#self.finger_base = mesh.Mesh(
#np.zeros(, dtype=mesh.Mesh.dtype))
# linear projection
# extrude lines in 1 direction
# cylinder / circular projection
# extrude lines in direction of a suitable cylinder
# normal projection
# extrude lines in the direction of normals of given finger model
image = app()

Loading…
Cancel
Save