Instructions to use hansQAQ/icip_source_2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use hansQAQ/icip_source_2 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("hansQAQ/icip_source_2", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
| import numpy as np | |
| import open3d as o3d | |
| import pymeshlab | |
| import torch | |
| import trimesh | |
| from pymeshlab import Percentage | |
| ### Mesh Utils ### | |
| ##### read mesh | |
| def read_mesh_from_path(mesh_path): | |
| ms = pymeshlab.MeshSet() | |
| ms.load_new_mesh(mesh_path) | |
| return ms | |
| def mesh_to_meshlab(vertices, faces): | |
| mesh = pymeshlab.Mesh(vertex_matrix=vertices, face_matrix=faces) | |
| ms = pymeshlab.MeshSet() | |
| ms.add_mesh(mesh) | |
| return ms | |
| def meshlab_to_mesh(ms): | |
| m = ms.current_mesh() | |
| return m.vertex_matrix(), m.face_matrix(), m.vertex_normal_matrix() | |
| ##### decimation | |
| def decimate_quadric_edge_collapse_with_texture( | |
| ms, targetfacenum=None, preservenormal=True, verbose=False | |
| ): | |
| # targetfacenum: int, Target number of faces. | |
| # preservenormal: bool, Preserve the normals of the original mesh. | |
| if verbose: | |
| print("Starting decimation ... ") | |
| m = ms.current_mesh() | |
| if targetfacenum is None: | |
| targetfacenum = int(m.face_number() * 0.5) | |
| if verbose: | |
| print("... Initial face number is %d ... " % m.face_number()) | |
| ms.meshing_decimation_quadric_edge_collapse_with_texture( | |
| targetfacenum=targetfacenum, preservenormal=preservenormal | |
| ) | |
| if verbose: | |
| print("... Decimated face number is %d ... " % m.face_number()) | |
| print("Decimation done!\n ") | |
| def decimate_quadric_edge_collapse( | |
| ms, targetfacenum=None, preservenormal=True, verbose=False | |
| ): | |
| # targetfacenum: int, Target number of faces. | |
| # preservenormal: bool, Preserve the normals of the original mesh. | |
| if verbose: | |
| print("Starting decimation ... ") | |
| m = ms.current_mesh() | |
| if targetfacenum is None: | |
| targetfacenum = int(m.face_number() * 0.5) | |
| if verbose: | |
| print("... Initial face number is %d ... " % m.face_number()) | |
| ms.meshing_decimation_quadric_edge_collapse( | |
| targetfacenum=targetfacenum, preservenormal=preservenormal | |
| ) | |
| if verbose: | |
| print("... Decimated face number is %d ... " % m.face_number()) | |
| print("Decimation done!\n ") | |
| ##### vertex merge | |
| def merge_close_vertices(ms, threshold=0.0001, verbose=False): | |
| # threshold: float, Merge together all the vertices that are nearer than the specified threshold. | |
| if verbose: | |
| print("Starting merge vertices ... ") | |
| m = ms.current_mesh() | |
| if verbose: | |
| print("... Initial vertex number is %d ... " % m.vertex_number()) | |
| ms.meshing_merge_close_vertices(threshold=Percentage(threshold * 100)) | |
| if verbose: | |
| print("... Merged vertex number is %d ... " % m.vertex_number()) | |
| print("Merge vertices done!\n ") | |
| ##### Island Removal | |
| def remove_isolated_pieces(ms, mincomponentsize=25, diameter=None, verbose=False): | |
| # mincomponentsize: Delete isolated connected components composed by a limited number of triangles | |
| # diameter: Delete isolated connected components whose diameter is smaller than the specified constant | |
| if verbose: | |
| print("Starting remove isolated pieces ... ") | |
| m = ms.current_mesh() | |
| if verbose: | |
| print("... Initial face number is %d ... " % m.face_number()) | |
| if diameter is None: | |
| ms.meshing_remove_connected_component_by_face_number( | |
| mincomponentsize=mincomponentsize, removeunref=True | |
| ) | |
| else: | |
| ms.meshing_remove_connected_component_by_diameter( | |
| mincomponentdiag=Percentage(diameter), removeunref=True | |
| ) | |
| if verbose: | |
| print("... Isolated removed face number is %d ... " % m.face_number()) | |
| print("Remove isolated pieces done!\n ") | |
| ##### hole filling | |
| def fix_hole(ms, maxholesize=30, verbose=False): | |
| # maxholesize: int, Maximum size of the hole to be filled. | |
| if verbose: | |
| print("Starting fix holes ... ") | |
| m = ms.current_mesh() | |
| if verbose: | |
| print("... Initial face number is %d ... " % m.face_number()) | |
| ms.meshing_close_holes(maxholesize=maxholesize) | |
| if verbose: | |
| print("... Fixed hole face number is %d ... " % m.face_number()) | |
| print("Fix holes done!\n ") | |
| ##### repair non manifold edges | |
| def repair_non_manifold(ms, verbose=False): | |
| if verbose: | |
| print("Starting repair non manifold edges ... ") | |
| m = ms.current_mesh() | |
| if verbose: | |
| print("... Initial face number is %d ... " % m.face_number()) | |
| ms.meshing_repair_non_manifold_edges() | |
| ms.meshing_repair_non_manifold_vertices(vertdispratio=0.1) | |
| ms.meshing_remove_duplicate_faces() | |
| if verbose: | |
| print("... Fixed non manifold edges face number is %d ... " % m.face_number()) | |
| print("Repair non manifold edges done!\n ") | |
| ##### laplacian_smooth | |
| def laplacian_smooth(ms, stepsmoothnum=3, verbose=False): | |
| # stepsmoothnum: int, Number of smoothing steps to be performed | |
| if verbose: | |
| print("Starting laplacian smooth ... ") | |
| m = ms.current_mesh() | |
| ms.apply_coord_laplacian_smoothing(stepsmoothnum=stepsmoothnum) | |
| if verbose: | |
| print("Laplacian smooth done!\n ") | |
| ##### taubin_smooth | |
| def taubin_smooth(ms, stepsmoothnum=3, verbose=False): | |
| if verbose: | |
| print("Starting Taubin smooth ... ") | |
| m = ms.current_mesh() | |
| ms.apply_coord_taubin_smoothing(stepsmoothnum=stepsmoothnum) | |
| if verbose: | |
| print("Taubin smooth done!\n ") | |
| ##### compute_normal | |
| def compute_normal(ms, weightmode="Simple Average", verbose=False): | |
| if verbose: | |
| print("Starting compute_normal_per_vertex ... ") | |
| m = ms.current_mesh() | |
| ms.compute_normal_per_vertex(weightmode=weightmode) | |
| if verbose: | |
| print("compute_normal_per_vertex done!\n ") | |
| ### Pre-process Mesh ### | |
| def process_mesh( | |
| vertices, | |
| faces, | |
| threshold=0.0001, | |
| mincomponentRatio=0.02, | |
| targetfacenum=50000, | |
| maxholesize=30, | |
| stepsmoothnum=10, | |
| verbose=False, | |
| ): | |
| ms = mesh_to_meshlab(vertices, faces) | |
| ### Vertex Merge | |
| merge_close_vertices(ms, threshold=threshold, verbose=verbose) | |
| ### Island Removal | |
| faces = ms.current_mesh().face_matrix() | |
| remove_isolated_pieces( | |
| ms, mincomponentsize=int(len(faces) * mincomponentRatio), verbose=verbose | |
| ) | |
| ### Hole Filling | |
| repair_non_manifold(ms) # repair before fix hole | |
| fix_hole(ms, maxholesize=maxholesize, verbose=verbose) | |
| ### Taubin Smoothing | |
| taubin_smooth(ms, stepsmoothnum=stepsmoothnum, verbose=verbose) | |
| vertices, faces, _ = meshlab_to_mesh(ms) | |
| if faces.shape[0] > targetfacenum: | |
| device = o3d.core.Device("CPU:0") | |
| dtype_f = o3d.core.float32 | |
| dtype_i = o3d.core.int64 | |
| mesh = o3d.t.geometry.TriangleMesh(device) | |
| mesh.vertex.positions = o3d.core.Tensor( | |
| vertices.astype(np.float32), dtype_f, device | |
| ) | |
| mesh.triangle.indices = o3d.core.Tensor(faces.astype(np.int64), dtype_i, device) | |
| simplified_mesh = mesh.simplify_quadric_decimation( | |
| target_reduction=1.0 - float(targetfacenum) / faces.shape[0] | |
| ) | |
| ms.clear() | |
| vertices = simplified_mesh.vertex.positions.numpy() | |
| faces = simplified_mesh.triangle.indices.numpy() | |
| mesh = pymeshlab.Mesh(vertex_matrix=vertices, face_matrix=faces) | |
| ms.add_mesh(mesh) | |
| ### Mesh Simplification/Decimation | |
| # decimate_quadric_edge_collapse(ms, targetfacenum=targetfacenum, verbose=verbose) | |
| taubin_smooth(ms, stepsmoothnum=stepsmoothnum, verbose=verbose) | |
| repair_non_manifold(ms, verbose=verbose) | |
| compute_normal(ms, verbose=verbose) | |
| return meshlab_to_mesh(ms) | |
| ### UV Un-Warp ### | |
| def uv_parameterize_uvatlas( | |
| vertices, | |
| faces, | |
| size=1024, | |
| gutter=2.5, | |
| max_stretch=0.1666666716337204, | |
| parallel_partitions=16, | |
| nthreads=0, | |
| ): | |
| device = o3d.core.Device("CPU:0") | |
| dtype_f = o3d.core.float32 | |
| dtype_i = o3d.core.int64 | |
| mesh = o3d.t.geometry.TriangleMesh(device) | |
| mesh.vertex.positions = o3d.core.Tensor( | |
| vertices.astype(np.float32), dtype_f, device | |
| ) | |
| mesh.triangle.indices = o3d.core.Tensor(faces.astype(np.int64), dtype_i, device) | |
| mesh.compute_uvatlas( | |
| size=size, | |
| gutter=gutter, | |
| max_stretch=max_stretch, | |
| parallel_partitions=parallel_partitions, | |
| nthreads=nthreads, | |
| ) | |
| return mesh.triangle.texture_uvs.numpy() # (#F, 3, 2) | |
| ### Pack All ### | |
| def process_raw(mesh_path, save_path, preprocess=True, device="cpu"): | |
| scene = trimesh.load(mesh_path, force="mesh", process=False) | |
| if isinstance(scene, trimesh.Trimesh): | |
| mesh = scene | |
| elif isinstance(scene, trimesh.scene.Scene): | |
| mesh = trimesh.Trimesh() | |
| for obj in scene.geometry.values(): | |
| mesh = trimesh.util.concatenate([mesh, obj]) | |
| else: | |
| raise ValueError(f"Unknown mesh type at {mesh_path}.") | |
| vertices = mesh.vertices | |
| faces = mesh.faces | |
| mesh_post_process_options = { | |
| "mincomponentRatio": 0.02, | |
| "targetfacenum": 50000, | |
| "maxholesize": 100, | |
| "stepsmoothnum": 10, | |
| "verbose": False, | |
| } | |
| if preprocess: | |
| v_pos, t_pos_idx, normals = process_mesh( | |
| vertices=vertices, | |
| faces=faces, | |
| **mesh_post_process_options, | |
| ) | |
| else: | |
| v_pos, t_pos_idx, normals = vertices, faces, mesh.vertex_normals | |
| v_tex_np = ( | |
| uv_parameterize_uvatlas(v_pos, t_pos_idx).reshape(-1, 2).astype(np.float32) | |
| ) | |
| v_pos = torch.from_numpy(v_pos).to(device=device, dtype=torch.float32) | |
| t_pos_idx = torch.from_numpy(t_pos_idx).to(device=device, dtype=torch.long) | |
| v_tex = torch.from_numpy(v_tex_np).to(device=device, dtype=torch.float32) | |
| normals = torch.from_numpy(normals).to(device=device, dtype=torch.float32) | |
| assert v_tex.shape[0] == t_pos_idx.shape[0] * 3 | |
| t_tex_idx = torch.arange( | |
| t_pos_idx.shape[0] * 3, | |
| device=device, | |
| dtype=torch.long, | |
| ).reshape(-1, 3) | |
| # uv, index = torch.unique(v_tex, dim=0, return_inverse=True) # 这样实现是2毫秒 | |
| # super efficient de-duplication | |
| v_tex_u_uint32 = v_tex_np[..., 0].view(np.uint32) | |
| v_tex_v_uint32 = v_tex_np[..., 1].view(np.uint32) | |
| v_hashed = (v_tex_u_uint32.astype(np.uint64) << 32) | v_tex_v_uint32 | |
| v_hashed = torch.from_numpy(v_hashed.view(np.int64)).to(v_pos.device) | |
| t_pos_idx_f3 = torch.arange( | |
| t_pos_idx.shape[0] * 3, device=t_pos_idx.device, dtype=torch.long | |
| ).reshape(-1, 3) | |
| v_pos_f3 = v_pos[t_pos_idx].reshape(-1, 3) | |
| normals_f3 = normals[t_pos_idx].reshape(-1, 3) | |
| v_hashed_dedup, inverse_indices = torch.unique(v_hashed, return_inverse=True) | |
| dedup_size, full_size = v_hashed_dedup.shape[0], inverse_indices.shape[0] | |
| indices = torch.scatter_reduce( | |
| torch.full( | |
| [dedup_size], | |
| fill_value=full_size, | |
| device=inverse_indices.device, | |
| dtype=torch.long, | |
| ), | |
| index=inverse_indices, | |
| src=torch.arange(full_size, device=inverse_indices.device, dtype=torch.int64), | |
| dim=0, | |
| reduce="amin", | |
| ) | |
| v_tex = v_tex[indices] | |
| t_tex_idx = inverse_indices.reshape(-1, 3) | |
| v_pos = v_pos_f3[indices] | |
| normals = normals_f3[indices] | |
| normals = normals.to(dtype=torch.float32, device=device) | |
| # either flip uv or flip texture | |
| # here we flip uv | |
| uv_to_save = v_tex.clone() | |
| uv_to_save[:, 1] = 1.0 - uv_to_save[:, 1] | |
| visual = trimesh.visual.TextureVisuals(uv=uv_to_save.cpu().numpy()) | |
| tmesh = trimesh.Trimesh( | |
| vertices=v_pos.cpu().numpy(), | |
| faces=t_tex_idx.cpu().numpy(), | |
| vertex_normals=normals.cpu().numpy(), | |
| visual=visual, | |
| process=False, | |
| ) | |
| tmesh.export(save_path) | |