diff --git a/src/main.py b/src/main.py index ae089aa..6ff1203 100644 --- a/src/main.py +++ b/src/main.py @@ -21,14 +21,13 @@ from stl import mesh import filters as flt -class apply_filters: +class app: def __init__(self): # Parse arguments from command line self.parse_arguments() self.params = {} self.filters = [] - # Parse configuration from json file if self.args.config: self.config_file = self.args.config[0] @@ -56,6 +55,11 @@ class apply_filters: self.params[i][key] = value 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.output_file = self.args.output_file self.dpi = self.args.dpi @@ -133,7 +137,7 @@ class apply_filters: parser = ap.ArgumentParser(prog='main.py', description='Program for processing a 2D image into 3D fingerprint.', 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 parser.add_argument("input_file", type=str, @@ -147,11 +151,12 @@ class apply_filters: type=bool, action=ap.BooleanOptionalAction) # 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 # 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') # 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 ''' - # TODO make this automatic for positive STL print("Mirroring image", file=sys.stderr) self.img = cv.flip(self.img, 1) # 1 for vertical mirror @@ -211,10 +215,12 @@ class apply_filters: print("Making meshgrid", file=sys.stderr) self.make_meshgrid() 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() - print(f"Saving lithophane to ", self.args.stl_file, file=sys.stderr) - self.save_mesh() + print(f"Saving lithophane to ", self.stl_file, file=sys.stderr) + self.save_stl() def make_meshgrid(self): ''' Create numpy meshgrid. @@ -227,27 +233,23 @@ class apply_filters: self.img = self.img * 255 self.img = self.img.astype(np.uint8) - # Make depth map from image - # TODO make this depth/height a param - 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 - self.height = self.img.shape[0] - self.width = self.img.shape[1] - self.print_size(self.img.shape) + print("Total depth:", self.depth_total, "mm, line depth/height:", self.depth_line, "mm") + depth_base = self.depth_total - self.depth_line + # Make depth map from image + if self.depth_line < 0: + self.img = (depth_base + (1 - self.img/255) * self.depth_line) + else: + self.img = (depth_base + (1 - self.img/255) * self.depth_line) + # Create meshgrid for 3D model - # This sets the scale of stl model - # TODO this is an absolutely random constant that fits the scale... - x = np.linspace(0, self.width / 23.6715, self.width) - y = np.linspace(0, self.height / 23.6715, self.height) + # This sets the scale of stl model and number of subdivisions / triangles + x = np.linspace(0, self.width * 25.4 / self.dpi, self.width) + y = np.linspace(0, self.height * 25.4 / self.dpi, self.height) + self.meshgrid = np.meshgrid(x, y) - def make_mesh(self): + def make_stl_planar(self): ''' Create mesh from image. Create vertices from meshgrid, add depth values from image. Create faces from vertices. Add veectors to the model. @@ -283,7 +285,6 @@ class apply_filters: faces.append([c + 1, c + 3, c + 2]) return c + 4 - # TODO: this can be done more efficiently # Iterate over all vertices, create faces for i in range(self.height - 1): for j in range(self.width - 1): @@ -296,7 +297,6 @@ class apply_filters: count = add_faces(count) # Add faces for the backside of the lithophane - # TODO: this doesn't work, creates naked edges null_arr = np.copy(vertex_arr) for i in range(self.height): for j in range(self.width): @@ -359,11 +359,33 @@ class apply_filters: for j in range(3): self.stl_mesh.vectors[i][j] = vertices[face[j], :] - def save_mesh(self): + def save_stl(self): ''' 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()