def measure_all(fbasename=None, log=None, ml_version=ml_version): """Measures mesh geometry, aabb and topology.""" ml_script1_file = 'TEMP3D_measure_gAndT.mlx' if ml_version == '1.3.4BETA': file_out = 'TEMP3D_aabb.xyz' else: file_out = None ml_script1 = mlx.FilterScript(file_in=fbasename, file_out=file_out, ml_version=ml_version) compute.measure_geometry(ml_script1) compute.measure_topology(ml_script1) ml_script1.save_to_file(ml_script1_file) ml_script1.run_script(log=log, script_file=ml_script1_file) geometry = ml_script1.geometry topology = ml_script1.topology if ml_version == '1.3.4BETA': if log is not None: log_file = open(log, 'a') log_file.write( '***Axis Aligned Bounding Results for file "%s":\n' % fbasename) log_file.close() aabb = measure_aabb(file_out, log) else: aabb = geometry['aabb'] return aabb, geometry, topology
def create_debug_simple_mesh(): # skip if cached if config.USE_CACHED_FILES and os.path.exists(debug_simple_mesh_file_path): # replace world with this new mesh (comment this out for prod) world_file_path = debug_simple_mesh_file_path world = trimesh.load(world_file_path) world_size = max(world.extents) return debug_simple_mesh_script = mlx.FilterScript( file_in=input_file_path, file_out=debug_simple_mesh_file_path) # clean / simplify mesh clean_mesh(debug_simple_mesh_script) mlx.remesh.simplify(debug_simple_mesh_script, texture=True, target_perc=0.5, quality_thr=config.SIMPLIFICATION_MESH_QUALITY, preserve_boundary=True, boundary_weight=config.SIMPLIFICATION_EDGE_WEIGHT, optimal_placement=True, preserve_normal=False, planar_quadric=True, selected=False, extra_tex_coord_weight=config.SIMPLIFICATION_TEXTURE_WEIGHT, preserve_topology=True, quality_weight=False, autoclean=True) selection_crop_to_mesh_bounds(debug_simple_mesh_script) clean_mesh(debug_simple_mesh_script) debug_simple_mesh_script.run_script() # replace world with this new mesh (comment this out for prod) world_file_path = debug_simple_mesh_file_path world = trimesh.load(world_file_path) world_size = max(world.extents)
def perform_simplify_mesh(original_mesh_path, simplified_mesh_path, num_faces): #Check the input mesh number of faces (so that we do not decimate to a higher number of faces than original mesh) MetricsMeshDictionary = {} MetricsMeshDictionary = mlx.files.measure_topology(original_mesh_path) if (MetricsMeshDictionary['face_num'] <= num_faces): copyfile(original_mesh_path, simplified_mesh_path) return False # simplify simplified_meshScript = mlx.FilterScript( file_in=original_mesh_path, file_out=simplified_mesh_path, ml_version='2016.12') # Create FilterScript object mlx.remesh.simplify(simplified_meshScript, texture=False, faces=num_faces, target_perc=0.0, quality_thr=1.0, preserve_boundary=True, boundary_weight=1.0, preserve_normal=True, optimal_placement=True, planar_quadric=True, selected=False, extra_tex_coord_weight=1.0) simplified_meshScript.run_script() return True
def measure_topology(fbasename=None, log=None, ml_version=ml_version): """Measures mesh topology Args: fbasename (str): input filename. log (str): filename to log output Returns: dict: dictionary with the following keys: vert_num (int): number of vertices edge_num (int): number of edges face_num (int): number of faces unref_vert_num (int): number or unreferenced vertices boundry_edge_num (int): number of boundary edges part_num (int): number of parts (components) in the mesh. manifold (bool): True if mesh is two-manifold, otherwise false. non_manifold_edge (int): number of non_manifold edges. non_manifold_vert (int): number of non-manifold verices genus (int or str): genus of the mesh, either a number or 'undefined' if the mesh is non-manifold. holes (int or str): number of holes in the mesh, either a number or 'undefined' if the mesh is non-manifold. """ ml_script1_file = 'TEMP3D_measure_topology.mlx' ml_script1 = mlx.FilterScript(file_in=fbasename, ml_version=ml_version) compute.measure_topology(ml_script1) ml_script1.save_to_file(ml_script1_file) ml_script1.run_script(log=log, script_file=ml_script1_file) topology = ml_script1.topology return topology
def create_tile(tile_file_path, tile_mesh): # build the tile in meshlab tile_mesh_script = mlx.FilterScript( file_in=layer_file_path, file_out=tile_file_path) selection_crop_to_mesh_bounds(tile_mesh_script, mesh=tile_mesh) # mlx.remesh.simplify(tile_mesh_script, texture=True, target_perc=percentage, # quality_thr=config.SIMPLIFICATION_MESH_QUALITY, preserve_boundary=True, boundary_weight=config.SIMPLIFICATION_EDGE_WEIGHT, # optimal_placement=True, preserve_normal=True, # planar_quadric=True, selected=False, extra_tex_coord_weight=config.SIMPLIFICATION_TEXTURE_WEIGHT, # preserve_topology=True, quality_weight=False, autoclean=True) # sanity check selection_crop_to_mesh_bounds(tile_mesh_script) tile_mesh_script.run_script() # convert to gltf # gltf_raw_file_path = tile_file_path.replace('.obj', '_unprocessed.gltf') gltf_final_file_path = tile_file_path.replace('.obj', '.gltf') check_call([config.OBJ2GLTF_PATH, '-i', tile_file_path, '-o', gltf_final_file_path], cwd=output_path) # check_call([config.GLTF_OPTIMIZE_PATH, '-i', # gltf_raw_file_path, '-o', gltf_final_file_path, '--binary', '--removeNormals', '--smoothNormals', '--cesium'], cwd=output_path) # cleanup residual files os.unlink(tile_file_path) os.unlink(tile_file_path + '.mtl')
def measure_dimension(fbasename=None, log=None, axis1=None, offset1=0.0, axis2=None, offset2=0.0, ml_version=ml_version): """Measure a dimension of a mesh""" axis1 = axis1.lower() axis2 = axis2.lower() ml_script1_file = 'TEMP3D_measure_dimension.mlx' file_out = 'TEMP3D_measure_dimension.xyz' ml_script1 = mlx.FilterScript(file_in=fbasename, file_out=file_out, ml_version=ml_version) compute.section(ml_script1, axis1, offset1, surface=True) compute.section(ml_script1, axis2, offset2, surface=False) layers.delete_lower(ml_script1) ml_script1.save_to_file(ml_script1_file) ml_script1.run_script(log=log, script_file=ml_script1_file) for val in ('x', 'y', 'z'): if val not in (axis1, axis2): axis = val # ord: Get number that represents letter in ASCII # Here we find the offset from 'x' to determine the list reference # i.e. 0 for x, 1 for y, 2 for z axis_num = ord(axis) - ord('x') aabb = measure_aabb(file_out, log) dimension = { 'min': aabb['min'][axis_num], 'max': aabb['max'][axis_num], 'length': aabb['size'][axis_num], 'axis': axis } if log is None: print('\nFor file "%s"' % fbasename) print('Dimension parallel to %s with %s=%s & %s=%s:' % (axis, axis1, offset1, axis2, offset2)) print(' Min = %s, Max = %s, Total length = %s' % (dimension['min'], dimension['max'], dimension['length'])) else: log_file = open(log, 'a') log_file.write('\nFor file "%s"\n' % fbasename) log_file.write('Dimension parallel to %s with %s=%s & %s=%s:\n' % (axis, axis1, offset1, axis2, offset2)) log_file.write('min = %s\n' % dimension['min']) log_file.write('max = %s\n' % dimension['max']) log_file.write('Total length = %s\n' % dimension['length']) log_file.close() return dimension
def pc2stl(file_in="input.asc", file_out='out.stl'): proj = mlx.FilterScript(file_in=file_in, file_out=file_out, ml_version='2016.12') mlx.normals.point_sets(proj, neighbors=32, smooth_iteration=10) mlx.remesh.surface_poisson_screened(proj) mlx.clean.close_holes(proj, hole_max_edge=1000, selected=False, sel_new_face=True, self_intersection=True) mlx.layers.delete(proj) proj.run_script()
def simplify_mesh(path, output_path, num_faces=2048): import meshlabxml as mlx topology = mlx.files.measure_topology(str(path)) if topology["face_num"] <= num_faces: shutil.copy(path, output_path) return script = mlx.FilterScript(file_in=str(path), file_out=str(output_path)) mlx.remesh.simplify(script, texture=False, faces=num_faces, preserve_topology=False) script.run_script()
def mesh_smoothing(ap): meshlabserver_path = 'C:\\Program Files\\VCG\\MeshLab' os.environ['PATH'] = meshlabserver_path + os.pathsep + os.environ['PATH'] obj_in = ap["test_dir_path"]+ap["inp_name"]+"_c.obj" obj_out = ap["test_dir_path"]+ap["inp_name"]+"_smooth.obj" mesh0 = mlx.FilterScript(file_in=obj_in, file_out=obj_out, ml_version='2016.12') # mlx.select.vert_function(mesh0, function='(r==255)',strict_face_select=False) mlx.select.face_function(mesh0, function='(r0==255)||(r1==255)||(r2==255)') # mlx.select.face_function(mesh0, function='(fr==255)') # mlx.delete.selected(mesh0) # mlx.select.face_function(mesh0, function='(abs(fi-5000)<1000)') mlx.smooth.taubin(mesh0, iterations=10, selected=True) mlx.smooth.laplacian(mesh0,iterations=1,selected=True) mlx.smooth.taubin(mesh0,iterations=100,selected=True) # mlx.smooth.laplacian(mesh0,iterations=5,selected=True) mesh0.run_script(log=ap["test_dir_path"]+"mesh0Log.txt")
def smooth_ply(ply_data): # Store ply_data in temporary file tmp_ply_filename = tempfile.mktemp(suffix=".ply") with open(tmp_ply_filename, 'w') as tmp_ply_file: ply_data.write(tmp_ply_file) # Initialize meshlabserver and meshlabxml script unsmoothed_mesh = meshlabxml.FilterScript(file_in=tmp_ply_filename, file_out=tmp_ply_filename, ml_version="1.3.2") meshlabxml.smooth.laplacian(unsmoothed_mesh, iterations=6) unsmoothed_mesh.run_script(print_meshlabserver_output=False, skip_error=True) # Read back and store new data with open(tmp_ply_filename, 'r') as tmp_ply_file: ply_data_smoothed = plyfile.PlyData.read(tmp_ply_file) return ply_data_smoothed
def measure_section(fbasename=None, log=None, axis='z', offset=0.0, rotate_x_angle=None, ml_version=ml_version): """Measure a cross section of a mesh Perform a plane cut in one of the major axes (X, Y, Z). If you want to cut on a different plane you will need to rotate the model in place, perform the cut, and rotate it back. Args: fbasename (str): filename of input model log (str): filename of log file axis (str): axis perpendicular to the cutting plane, e.g. specify "z" to cut parallel to the XY plane. offset (float): amount to offset the cutting plane from the origin rotate_x_angle (float): degrees to rotate about the X axis. Useful for correcting "Up" direction: 90 to rotate Y to Z, and -90 to rotate Z to Y. Returns: dict: dictionary with the following keys for the aabb of the section: min (list): list of the x, y & z minimum values max (list): list of the x, y & z maximum values center (list): the x, y & z coordinates of the center of the aabb size (list): list of the x, y & z sizes (max - min) diagonal (float): the diagonal of the aabb """ ml_script1_file = 'TEMP3D_measure_section.mlx' file_out = 'TEMP3D_sect_aabb.xyz' ml_script1 = mlx.FilterScript(file_in=fbasename, file_out=file_out, ml_version=ml_version) if rotate_x_angle is not None: transform.rotate(ml_script1, axis='x', angle=rotate_x_angle) compute.section(ml_script1, axis=axis, offset=offset) layers.delete_lower(ml_script1) ml_script1.save_to_file(ml_script1_file) ml_script1.run_script(log=log, script_file=ml_script1_file) aabb = measure_aabb(file_out, log) return aabb
def create_layer(layer_file_path, percentage): # skip if cached if config.USE_CACHED_FILES and os.path.exists(layer_file_path): return layer_mesh_script = mlx.FilterScript( file_in=world_file_path, file_out=layer_file_path) # clean / simplify mesh clean_mesh(layer_mesh_script) mlx.remesh.simplify(layer_mesh_script, texture=True, target_perc=percentage, quality_thr=config.SIMPLIFICATION_MESH_QUALITY, preserve_boundary=True, boundary_weight=config.SIMPLIFICATION_EDGE_WEIGHT, optimal_placement=True, preserve_normal=False, planar_quadric=True, selected=False, extra_tex_coord_weight=config.SIMPLIFICATION_TEXTURE_WEIGHT, preserve_topology=True, quality_weight=False, autoclean=True) selection_crop_to_mesh_bounds(layer_mesh_script) clean_mesh(layer_mesh_script) layer_mesh_script.run_script() layer_gltf_file_path = layer_file_path.replace('.obj', '.gltf') check_call([config.OBJ2GLTF_PATH, '-i', tile_file_path, '-o', layer_gltf_file_path], cwd=output_path)
#exit the script and print a message about it print( "\n SORRY your decimated mesh can not have higher number of faces that the input mesh....." ) print( "\n ......................................................................................" ) sys.exit() #Creating a folder named as the Number of faces: named '150000' print('\n Creating a folder to store the decimated model ...........') if not os.path.exists(str(Num_Of_Faces)): os.makedirs(str(Num_Of_Faces)) simplified_meshScript = mlx.FilterScript( file_in=original_mesh, file_out=str(Num_Of_Faces) + '/' + simplified_mesh, ml_version='2016.12') # Create FilterScript object mlx.remesh.simplify(simplified_meshScript, texture=TexturesFlag, faces=Num_Of_Faces, target_perc=0.0, quality_thr=1.0, preserve_boundary=True, boundary_weight=1.0, preserve_normal=True, optimal_placement=True, planar_quadric=True, selected=False, extra_tex_coord_weight=1.0) print('\n Beginning the process of Decimation ...........')
def quatrefoil(): """ Rainbow colored voronoi quatrefoil (3,4) torus knot """ start_time = time.time() os.chdir(THIS_SCRIPTPATH) #ml_version = '1.3.4BETA' ml_version = '2016.12' # Add meshlabserver directory to OS PATH; omit this if it is already in # your PATH #meshlabserver_path = 'C:\\Program Files\\VCG\\MeshLab' #""" if ml_version == '1.3.4BETA': meshlabserver_path = 'C:\\Program Files\\VCG\\MeshLab' elif ml_version == '2016.12': meshlabserver_path = 'C:\\Program Files\\VCG\\MeshLab_2016_12' #""" os.environ['PATH'] = meshlabserver_path + os.pathsep + os.environ['PATH'] # Cross section parameters length = math.radians(360) tube_size = [10, 10, length] segments = [64, 64, 720 * 2] inner_radius = 2.0 # Sinusoidal deformation parameters amplitude = 4.2 freq = 4 phase = 270 center = 'r' start_pt = 0 increment = 'z-{}'.format(start_pt) # Cyclic rainbow color parameters c_start_pt = 0 c_freq = 5 c_phase_shift = 0 #90 #300 c_phase = (0 + c_phase_shift, 120 + c_phase_shift, 240 + c_phase_shift, 0) # Voronoi surface parameters holes = [2, 2, 44] # Number of holes in each axis; x are sides, y is outside web_thickness = 0.5 solid_radius = 5.0 # If the mesh is smaller than this radius the holes will be closed faces_surface = 50000 # Voronoi solid parameters voxel = 0.5 thickness = 2.5 faces_solid = 200000 # Scaling parameters size = 75 # desired max size of the curve curve_max_size = 2 * ( 1 + 1.5) # the 1.5 s/b inner_radius, but am keepng current scaling scale = (size - 2 * (thickness + amplitude) - tube_size[1]) / curve_max_size # File names file_color = 'quatrefoil_color.ply' file_voronoi_surf = 'quatrefoil_voronoi_surf.ply' file_voronoi_solid = 'quatrefoil_voronoi_solid.ply' file_voronoi_color = 'quatrefoil_voronoi_final.ply' # Create FilterScript objects for each step in the process quatrefoil_color = mlx.FilterScript(file_in=None, file_out=file_color, ml_version=ml_version) quatrefoil_voronoi_surf = mlx.FilterScript(file_in=file_color, file_out=file_voronoi_surf, ml_version=ml_version) quatrefoil_voronoi_solid = mlx.FilterScript(file_in=file_voronoi_surf, file_out=file_voronoi_solid, ml_version=ml_version) quatrefoil_voronoi_color = mlx.FilterScript( file_in=[file_color, file_voronoi_solid], file_out=file_voronoi_color, ml_version=ml_version) print('\n Create colored quatrefoil curve ...') mlx.create.cube_open_hires(quatrefoil_color, size=tube_size, x_segments=segments[0], y_segments=segments[1], z_segments=segments[2], center=True) mlx.transform.translate(quatrefoil_color, [0, 0, length / 2]) # Sinusoidal deformation r_func = '({a})*sin(({f})*({i}) + ({p})) + ({c})'.format( f=freq, i=increment, p=math.radians(phase), a=amplitude, c=center) mlx.transform.function_cyl_co(quatrefoil_color, r_func=r_func, theta_func='theta', z_func='z') # Save max radius in quality field so that we can save it with the file # for use in the next step max_radius = math.sqrt( (tube_size[0] / 2)**2 + (tube_size[1] / 2)**2) # at corners q_func = '({a})*sin(({f})*({i}) + ({p})) + ({c})'.format( f=freq, i=increment, p=math.radians(phase), a=amplitude, c=max_radius) mlx.mp_func.vq_function(quatrefoil_color, function=q_func) # Apply rainbow vertex colors mlx.vert_color.cyclic_rainbow(quatrefoil_color, direction='z', start_pt=c_start_pt, amplitude=255 / 2, center=255 / 2, freq=c_freq, phase=c_phase) # Deform mesh to quatrefoil curve. Merge vertices after, which # will weld the ends together so it becomes watertight quatrefoil_func = mlx.transform.deform2curve(quatrefoil_color, curve=mlx.mp_func.torus_knot( 't', p=3, q=4, scale=scale, radius=inner_radius)) mlx.clean.merge_vert(quatrefoil_color, threshold=0.0001) # Run script mlx.layers.delete_lower(quatrefoil_color) quatrefoil_color.run_script(output_mask='-m vc vq') print('\n Create Voronoi surface ...') # Move quality value into radius attribute mlx.mp_func.vert_attr(quatrefoil_voronoi_surf, name='radius', function='q') # Create seed vertices # For grid style holes, we will create a mesh similar to the original # but with fewer vertices. mlx.create.cube_open_hires(quatrefoil_voronoi_surf, size=tube_size, x_segments=holes[0] + 1, y_segments=holes[1] + 1, z_segments=holes[2] + 1, center=True) mlx.select.all(quatrefoil_voronoi_surf, vert=False) mlx.delete.selected(quatrefoil_voronoi_surf, vert=False) mlx.select.cylindrical_vert(quatrefoil_voronoi_surf, radius=max_radius - 0.0001, inside=False) mlx.transform.translate(quatrefoil_voronoi_surf, [0, 0, 20]) mlx.delete.selected(quatrefoil_voronoi_surf, face=False) mlx.transform.function_cyl_co(quatrefoil_voronoi_surf, r_func=r_func, theta_func='theta', z_func='z') mlx.transform.vert_function(quatrefoil_voronoi_surf, x_func=quatrefoil_func[0], y_func=quatrefoil_func[1], z_func=quatrefoil_func[2]) mlx.layers.change(quatrefoil_voronoi_surf, 0) mlx.vert_color.voronoi(quatrefoil_voronoi_surf) if quatrefoil_voronoi_surf.ml_version == '1.3.4BETA': sel_func = '(q <= {}) or ((radius)<={})'.format( web_thickness, solid_radius) else: sel_func = '(q <= {}) || ((radius)<={})'.format( web_thickness, solid_radius) mlx.select.vert_function(quatrefoil_voronoi_surf, function=sel_func) #mlx.select.face_function(quatrefoil_voronoi_surf, function='(vsel0 && vsel1 && vsel2)') mlx.select.invert(quatrefoil_voronoi_surf, face=False) mlx.delete.selected(quatrefoil_voronoi_surf, face=False) mlx.smooth.laplacian(quatrefoil_voronoi_surf, iterations=3) mlx.remesh.simplify(quatrefoil_voronoi_surf, texture=False, faces=faces_surface) mlx.layers.delete_lower(quatrefoil_voronoi_surf) #quatrefoil_voronoi_surf.save_to_file('temp_script.mlx') quatrefoil_voronoi_surf.run_script(script_file=None, output_mask='-m vc vq') print('\n Solidify Voronoi surface ...') mlx.remesh.uniform_resampling(quatrefoil_voronoi_solid, voxel=voxel, offset=thickness / 2, thicken=True) mlx.layers.delete_lower(quatrefoil_voronoi_solid) quatrefoil_voronoi_solid.run_script() print('\n Clean up & transfer color to final model ...') # Clean up from uniform mesh resamplng mlx.delete.small_parts(quatrefoil_voronoi_color) mlx.delete.unreferenced_vert(quatrefoil_voronoi_color) mlx.delete.faces_from_nonmanifold_edges(quatrefoil_voronoi_color) mlx.clean.split_vert_on_nonmanifold_face(quatrefoil_voronoi_color) mlx.clean.close_holes(quatrefoil_voronoi_color) # Simplify (to improve triangulation quality), refine, & smooth mlx.remesh.simplify(quatrefoil_voronoi_color, texture=False, faces=faces_solid) mlx.subdivide.ls3loop(quatrefoil_voronoi_color, iterations=1) mlx.smooth.laplacian(quatrefoil_voronoi_color, iterations=3) # Transfer colors from original curve mlx.transfer.vert_attr_2_meshes(quatrefoil_voronoi_color, source_mesh=0, target_mesh=1, color=True, max_distance=7) mlx.layers.delete_lower(quatrefoil_voronoi_color) quatrefoil_voronoi_color.run_script(script_file=None) print(' done! Took %.1f sec' % (time.time() - start_time)) return None
def simplify(originalMeshName, SimplifiedMeshName, NumberOfFaces, WithTexture): # File names FilterScript = 'SimplificationFilter.mlx' # script file original_mesh = originalMeshName # input file simplified_mesh = SimplifiedMeshName # output file Num_Of_Faces = int(NumberOfFaces) # Final Number of Faces #Check the input mesh number of faces (so that we do not decimate to a higher number of faces than original mesh) MetricsMeshDictionary = {} MetricsMeshDictionary = mlx.files.measure_topology(original_mesh) #print (MetricsMeshDictionary) print('\n Number of faces of original mesh is: ' + str(MetricsMeshDictionary['face_num'])) if (MetricsMeshDictionary['face_num'] <= Num_Of_Faces): #exit the script and print a message about it print( "\n SORRY your decimated mesh can not have higher number of faces that the input mesh....." ) print( "\n ......................................................................................" ) sys.exit() #Creating a folder named as the Number of faces: named '150000' print('\n Creating a folder to store the decimated model ...........') if not os.path.exists(str(Num_Of_Faces)): os.makedirs(str(Num_Of_Faces)) simplified_meshScript = mlx.FilterScript( file_in=original_mesh, file_out=str(Num_Of_Faces) + '/' + simplified_mesh, ml_version='2016.12') # Create FilterScript object mlx.remesh.simplify(simplified_meshScript, texture=WithTexture, faces=Num_Of_Faces, target_perc=0.0, quality_thr=1.0, preserve_boundary=True, boundary_weight=1.0, preserve_normal=True, optimal_placement=True, planar_quadric=True, selected=False, extra_tex_coord_weight=1.0) print('\n Beginning the process of Decimation ...........') simplified_meshScript.run_script() # Run the script os.chdir(str(Num_Of_Faces)) print('\n Process of Decimation Finished ...') print( '\n Copying textures (PNG and JPEG) into the folder of decimated model....' ) #go back to parent directory so we can copy the textures to the 3D Model folder os.chdir('..') #Now checking for textures in the folder of the input mesh.... (plz change if needed) allfilelist = os.listdir('.') for Afile in allfilelist[:]: if not (Afile.endswith(".png") or Afile.endswith(".PNG") or Afile.endswith(".jpg") or Afile.endswith(".JPG")): allfilelist.remove(Afile) print('\n Found the LIST of images in PNG and JPEG (textures): ') print(allfilelist) for file in allfilelist: shutil.copy(file, str(Num_Of_Faces)) print('\n sleeping for 3 seconds.... ') time.sleep(3)
def stack_to_mesh(input_folder, mesh_folder, sigma=3): basename = os.path.basename(input_folder) # VTK imgdata = vtk_functions.folder_to_imgdata(input_folder) if sigma > 0: padding = sigma * 4 imgdata = vtk_functions.pad_imgdata(imgdata, padding) imgdata = vtk_functions.gauss_imgdata(imgdata, sigma=sigma) print("Applied Gaussian smoothing with s=%s" % sigma) basename = basename + "_g_%s" % sigma ply_file_name = "%s/%s.ply" % (mesh_folder, basename) polydata = vtk_functions.imgdata_to_pd(imgdata) vtk_functions.write_ply(polydata, ply_file_name) # MESHLAB input_mesh = ply_file_name output_mesh = "%s/%s_MLX.ply" % (mesh_folder, basename) mesh_topology = mlx.files.measure_topology(input_mesh) target_faces = int(np.round(mesh_topology["face_num"] * target_reduction)) simplified_mesh = mlx.FilterScript(file_in=input_mesh, file_out=output_mesh) # Apply decimation t_faces = int(np.round(mesh_topology["face_num"] * 0.5**1)) mlx.remesh.simplify(simplified_mesh, texture=False, faces=t_faces, quality_thr=1, preserve_topology=False, preserve_boundary=True) t_faces = int(np.round(mesh_topology["face_num"] * 0.5**2)) mlx.remesh.simplify(simplified_mesh, texture=False, faces=t_faces, quality_thr=1, preserve_topology=False, preserve_boundary=True) t_faces = int(np.round(mesh_topology["face_num"] * 0.5**3)) mlx.remesh.simplify(simplified_mesh, texture=False, faces=t_faces, quality_thr=1, preserve_topology=False, preserve_boundary=True) t_faces = int(np.round(mesh_topology["face_num"] * 0.5**4)) mlx.remesh.simplify(simplified_mesh, texture=False, faces=t_faces, quality_thr=1, preserve_topology=False, preserve_boundary=True) # Apply Taubin smoothing mlx.smooth.taubin(simplified_mesh, iterations=smoothing_iterations) simplified_mesh.run_script()
#Remesh ohne Meshlab (zum teil) #data_in = ("D:\Programmierung\Poisson_Recon\testing\hole.ply") data_in = os.path.join(pointcloud_filename + '.ply') #data_out = ("D:\Programmierung\Poisson_Recon\testing\holeneu.ply") data_out = os.path.join(pointcloud_filename + '_mesh.ply') depth = 10 scale = 1.003 samplePerNode = 3 pointWeight = 2 iters = 9 cmd = Path_poisson_recon + " --in " + data_in + ' --out '+ data_out + ' --depth '+ str(depth) + ' --scale '+ str(scale) + ' --samplePerNode '+ str(samplePerNode) + ' --pointWeight '+ str(pointWeight) + ' --iters '+ str(iters) sp.call(cmd) #Pointcloud_test_out = mlx.FilterScript(file_in = 'Pointcloud_test.ply', file_out = 'Pointcloud_remesh.stl', ml_version='2016.12') Pointcloud_test_out = mlx.FilterScript(file_in = data_out, file_out = os.path.join(remesh_filename + '.stl'), ml_version='2016.12') # mlx.remesh.surface_poisson_screened(Pointcloud_test_out,depth=10, # full_depth=5, cg_depth=0, scale=1.0092, # samples_per_node=3, point_weight=2.0, # iterations=8, confidence=False, pre_clean=False) # mlx.layers.delete(Pointcloud_test_out) mlx.remesh.simplify(Pointcloud_test_out, texture=False, faces=10000, target_perc=0.0, quality_thr=0.95, preserve_boundary=True, boundary_weight=10.0, optimal_placement=True, preserve_normal=True, planar_quadric=False, selected=False, extra_tex_coord_weight=1.0, preserve_topology=True, quality_weight=False, autoclean=True) Pointcloud_test_out.run_script() delta_time_remesh = round(time.time() - start_time_tracen, 6) os.remove(data_out) #convert to ascii encoding
import meshlabxml as mlx import sys original_mesh = sys.argv[1] # input file simplified_mesh = sys.argv[2] # output file simplified_mesh = mlx.FilterScript( file_in=original_mesh, file_out=simplified_mesh, ml_version='2016.12') # Create FilterScript object mlx.remesh.simplify(simplified_mesh, texture=False, faces=1000, target_perc=0.0, quality_thr=0.3) simplified_mesh.run_script() # Run the script
os.environ['DYLD_FRAMEWORK_PATH'] = meshlabserver_path + "/../Frameworks" # Example 1 #orange_cube = mlx.FilterScript(file_out='orange_cube.ply', # ml_version='2016.12') #mlx.create.cube(orange_cube, size=[3.0, 4.0, 5.0], center=True, color='orange') #mlx.transform.rotate(orange_cube, axis='x', angle=90) #mlx.transform.rotate(orange_cube, axis='y', angle=50) #mlx.transform.translate(orange_cube, value=[5.0, 5.0, 0]) #orange_cube.run_script() # Open a mesh -> implicit in the FilterScript # 2.) Define filters... # 3.) Find filters in the https://github.com/3DLIRIOUS/MeshLabXML repo # or in Python console import the package and use help, eg. help(mlx.clean) import_mesh = mlx.FilterScript(file_in='3D_human_mesh.ply', file_out='new_3D_human_mesh.obj') # First, some cleaning mlx.clean.merge_vert(import_mesh, threshold=0.003) mlx.delete.faces_from_nonmanifold_edges(import_mesh) mlx.delete.nonmanifold_edge(import_mesh) mlx.delete.nonmanifold_vert(import_mesh) #duplicate_verts() not found??? Some weird error #mlx.delete.duplicate_verts(import_mesh) mlx.delete.duplicate_faces(import_mesh) import_mesh.run_script()
def main(): """Run main script""" # segments = number of segments to use for circles segments = 50 # star_points = number of points (or sides) of the star star_points = 5 # star_radius = radius of circle circumscribing the star star_radius = 2 # ring_thickness = thickness of the colored rings ring_thickness = 1 # sphere_radius = radius of sphere the shield will be deformed to sphere_radius = 2 * (star_radius + 3 * ring_thickness) # Star calculations: # Visually approximate a star by using multiple diamonds (i.e. scaled # squares) which overlap in the center. For the star calculations, # consider a central polygon with triangles attached to the edges, all # circumscribed by a circle. # polygon_radius = distance from center of circle to polygon edge midpoint polygon_radius = star_radius / \ (1 + math.tan(math.radians(180 / star_points)) / math.tan(math.radians(90 / star_points))) # width = 1/2 width of polygon edge/outer triangle bottom width = polygon_radius * math.tan(math.radians(180 / star_points)) # height = height of outer triangle height = width / math.tan(math.radians(90 / star_points)) shield = mlx.FilterScript(file_out="shield.ply") # Create the colored front of the shield using several concentric # annuluses; combine them together and subdivide so we have more vertices # to give a smoother deformation later. mlx.create.annulus(shield, radius=star_radius, cir_segments=segments, color='blue') mlx.create.annulus(shield, radius1=star_radius + ring_thickness, radius2=star_radius, cir_segments=segments, color='red') mlx.create.annulus(shield, radius1=star_radius + 2 * ring_thickness, radius2=star_radius + ring_thickness, cir_segments=segments, color='white') mlx.create.annulus(shield, radius1=star_radius + 3 * ring_thickness, radius2=star_radius + 2 * ring_thickness, cir_segments=segments, color='red') mlx.layers.join(shield) mlx.subdivide.midpoint(shield, iterations=2) # Create the inside surface of the shield & translate down slightly so it # doesn't overlap the front. mlx.create.annulus(shield, radius1=star_radius + 3 * ring_thickness, cir_segments=segments, color='silver') mlx.transform.rotate(shield, axis='y', angle=180) mlx.transform.translate(shield, value=[0, 0, -0.005]) mlx.subdivide.midpoint(shield, iterations=4) # Create a diamond for the center star. First create a plane, specifying # extra vertices to support the final deformation. The length from the # center of the plane to the corners should be 1 for ease of scaling, so # we use a side length of sqrt(2) (thanks Pythagoras!). Rotate the plane # by 45 degrees and scale it to stretch it out per the calculations above, # then translate it into place (including moving it up in z slightly so # that it doesn't overlap the shield front). mlx.create.grid(shield, size=math.sqrt(2), x_segments=10, y_segments=10, center=True, color='white') mlx.transform.rotate(shield, axis='z', angle=45) mlx.transform.scale(shield, value=[width, height, 1]) mlx.transform.translate(shield, value=[0, polygon_radius, 0.001]) # Duplicate the diamond and rotate the duplicates around, generating the # star. for _ in range(1, star_points): mlx.layers.duplicate(shield) mlx.transform.rotate(shield, axis='z', angle=360 / star_points) # Combine everything together and deform using a spherical function. mlx.layers.join(shield) mlx.transform.vert_function(shield, z_func='sqrt(%s-x^2-y^2)-%s+z' % (sphere_radius**2, sphere_radius)) # Run the script using meshlabserver and generate the model shield.run_script() return None