From 68b9deaae3231d08b4bd6d33369ccc265555a935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rostislav=20L=C3=A1n?= Date: Sun, 8 Jan 2023 01:41:03 +0100 Subject: [PATCH] Added stl filename, fixed type conversion for image. --- src/main.py | 85 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/src/main.py b/src/main.py index eba7fc4..07238af 100644 --- a/src/main.py +++ b/src/main.py @@ -26,6 +26,7 @@ class apply_filters: self.parse_arguments() self.params = {} self.filters = [] + # Parse configuration from json file if self.args.config: @@ -57,6 +58,7 @@ class apply_filters: self.input_file = self.args.input_file self.output_file = self.args.output_file self.dpi = self.args.dpi + self.mirror = True if self.args.mirror else False self.run() def run(self): @@ -67,22 +69,22 @@ class apply_filters: self.width = self.img.shape[1] self.height = self.img.shape[0] self.print_size(self.img.shape) - - fig = plt.figure(figsize=(self.width, self.height), - frameon=False, dpi=self.dpi / 100) # dpi is in cm + print(self.dpi) + fig = plt.figure(figsize=(self.width/100, self.height/100), + frameon=False, dpi=self.dpi) ax = plt.Axes(fig, [0., 0., 1., 1.]) ax.set_axis_off() fig.add_axes(ax) - if self.args.mirror: + if self.mirror is True: self.mirror_image() # Apply all filters and save image self.apply_filter() self.save_image(fig, ax) plt.close() - if self.args.stl: + if self.args.stl_file: self.make_lithophane() def parse_params(self, params): @@ -125,7 +127,8 @@ 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 ...])') + 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]') # positional arguments parser.add_argument("input_file", type=str, @@ -135,12 +138,11 @@ class apply_filters: parser.add_argument("dpi", type=int, help="scanner dpi") # boolean switch argument - parser.add_argument('-m', "--mirror", help="mirror input image", + parser.add_argument('-m', "--mirror", help="mirror input image", type=bool, action=ap.BooleanOptionalAction) - # another boolean switch argument - parser.add_argument('-s', '--stl', help="make stl model from processed image", - 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) # file with configuration containing presets, new preset name # pair argument - give both or none @@ -160,12 +162,6 @@ class apply_filters: print("Applying " + filter_name + " filter ", end='') return getattr(flt, filter_name) - def resize_image(self): - - print("Resize image", file=sys.stderr) - self.img = self.img.resize( - (np.array(self.width, self.height)).astype(int)) - def mirror_image(self): ''' Mirror image when mirroring is needed, should be used only if we want a positive model @@ -178,7 +174,7 @@ class apply_filters: def apply_filter(self): ''' Apply filters to image. - Applies the filters one by one, if no filters were given, just save original image output. + Apply the filters one by one, if none were given, just save original image output. ''' if len(self.filters) == 0: @@ -188,9 +184,9 @@ class apply_filters: # Apply all filters for i, filter_name in enumerate(self.filters): filter = self.filter_factory(filter_name) - # print(self.img.dtype) + #print(self.img.dtype) filter.apply(self, self.params[i+1]) - # print(self.img.dtype) + #print(self.img.dtype) def print_size(self, size): print("Height: " + str(size[0]), file=sys.stderr) @@ -201,9 +197,9 @@ class apply_filters: Colormap set to grayscale to avoid color mismatch. ''' - print("Saving image", file=sys.stderr) + print("Saving image to ", self.output_file, file=sys.stderr) ax.imshow(self.img, cmap="gray") - fig.savefig(fname=self.output_file) + fig.savefig(fname=self.output_file, dpi='figure') def make_lithophane(self): '''After processing image, make a lithophane from it. @@ -214,28 +210,33 @@ class apply_filters: print("Converting to stl format", file=sys.stderr) self.make_mesh() plt.show() - self.save_model() + print(f"Saving lithophane to ", self.args.stl_file, file=sys.stderr) + self.save_mesh() def make_meshgrid(self): ''' Create numpy meshgrid. Modify image values to get more usable depth values. Add zero padding to image to make sides of the plate. ''' + + if self.img.dtype == np.float32 or self.img.dtype == np.float64: + print("Converting to uint8", file=sys.stderr) + self.img = self.img * 255 + self.img = self.img.astype(np.uint8) + # Modify image to make it more suitable depth - # values1 = (1 + (1 - self.img/255)/6) * 255/10 # this works - # values2 = (1 - (1 - self.img/255)/6) * 255/10 # + rescaled = (1 + (1 - self.img/255)/6) * 255 / 10 # for positive forms ? + if self.mirror is True: + rescaled = (2 - (1 - self.img/255)/6) * 255 / 10 # for negative forms + # TODO: i dont know how to make white surrounding be extruded - values1better = 28.05 - 0.01*self.img - #values2better = 22.95 - 0.01*self.img - # (np.around(values2[::300],3)) - # Add zero padding to image # TODO this better be done in the next function to keep dimensions intact self.height = self.img.shape[0] + 2 self.width = self.img.shape[1] + 2 self.img = np.zeros([self.height, self.width]) - self.img[1:-1:1, 1:-1:1] = values1better + self.img[1:-1:1, 1:-1:1] = rescaled # Create meshgrid for 3D model verticesX = np.around(np.linspace(0, self.width / 10, self.width), 3) @@ -245,7 +246,19 @@ class apply_filters: def make_mesh(self): ''' Create mesh from image. Create vertices from meshgrid, add depth values from image. - Create faces from vertices. + Create faces from vertices. Add veectors to the model. + + From wikipedia.org/wiki/STL_(file_format): + ascii stl format consists of repeating struictures: + + facet normal ni nj nk # normal vector + outer loop + vertex v1x v1y v1z # vertex 1 + vertex v2x v2y v2z # vertex 2 + vertex v3x v3y v3z # vertex 3 + endloop + endfacet + ''' # Convert meshgrid and image matrix to array of 3D points @@ -292,17 +305,17 @@ class apply_filters: vertices = np.array(vertices) # Create the mesh - self.model = mesh.Mesh(np.zeros(len(faces), dtype=mesh.Mesh.dtype)) + self.stl_mesh = mesh.Mesh(np.zeros(len(faces), dtype=mesh.Mesh.dtype)) for i, face in enumerate(faces): for j in range(3): - self.model.vectors[i][j] = vertices[face[j], :] + self.stl_mesh.vectors[i][j] = vertices[face[j], :] + self.stl_mesh.vectors[i][j] /= 2.54 # convert to inches - def save_model(self): - ''' Save final model to stl file. + def save_mesh(self): + ''' Save final mesh to stl file. ''' - print("Saving lithophane to stl file", file=sys.stderr) - self.model.save('res/test.stl') + self.stl_mesh.save(self.args.stl_file) image = apply_filters()