toshas commited on
Commit
c184ad2
1 Parent(s): fd20bb7

Initial commit

Browse files
Files changed (7) hide show
  1. .gitignore +5 -0
  2. Dockerfile +41 -0
  3. README.md +6 -5
  4. files/horse.ply +0 -0
  5. main.py +193 -0
  6. requirements.txt +3 -0
  7. thumbnail.jpg +0 -0
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ .idea
2
+ .DS_Store
3
+ __pycache__
4
+ gradio_cached_examples
5
+
Dockerfile ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM toshas/repainting_3d_assets:v2
2
+ ENTRYPOINT []
3
+
4
+ ENV DEBIAN_FRONTEND=noninteractive
5
+
6
+ ENV REPAINTING3D_DO_NOT_MANAGE_HFCACHE=1
7
+
8
+ ENV TRANSFORMERS_CACHE=/data/hfcache
9
+ ENV HF_DATASETS_CACHE=/data/hfcache
10
+ ENV HF_HOME=/data/hfcache
11
+
12
+ RUN mkdir -p ${HF_HOME}
13
+
14
+ RUN apt-get -y update --fix-missing && \
15
+ apt-get install -y \
16
+ python3 \
17
+ python3-pip \
18
+ && \
19
+ apt-get clean
20
+
21
+ WORKDIR ${ROOT_PROJECT}
22
+ RUN git clone https://github.com/kongdai123/repainting_3d_assets.git && \
23
+ rm -rf repainting_3d_assets/.git repainting_3d_assets/assets repainting_3d_assets/doc && \
24
+ rm -rf code && \
25
+ mv repainting_3d_assets code
26
+
27
+ COPY ./requirements.txt ./
28
+ RUN pip3 install --no-cache-dir --upgrade -r requirements.txt
29
+
30
+ RUN useradd -m -u 1000 user
31
+
32
+ RUN chown -R user ${HF_HOME}
33
+
34
+ USER user
35
+ ENV HOME=/home/user \
36
+ PATH=/home/user/.local/bin:$PATH
37
+
38
+ ENV PYTHONUNBUFFERED=1
39
+ WORKDIR ${HOME}/app
40
+ COPY --chown=user . ${HOME}/app
41
+ CMD ["python3", "main.py"]
README.md CHANGED
@@ -1,11 +1,12 @@
1
  ---
2
- title: Repainting 3d Assets
3
- emoji: 🏆
4
- colorFrom: gray
5
- colorTo: red
6
  sdk: docker
7
- pinned: false
8
  license: cc-by-nc-sa-4.0
 
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Repainting 3D Assets
3
+ emoji: 🦄
4
+ colorFrom: teal
5
+ colorTo: indigo
6
  sdk: docker
7
+ pinned: true
8
  license: cc-by-nc-sa-4.0
9
+ models: ["stabilityai/stable-diffusion-2-depth"]
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
files/horse.ply ADDED
Binary file (31.9 kB). View file
 
main.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import os
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ import gradio as gr
9
+ import pygltflib
10
+ import trimesh
11
+
12
+
13
+ def convert_formats(path_input, target_ext):
14
+ """
15
+ Converts an input 3D model under input path to the target extensions format and returns a path to that file.
16
+ :param path_input: path to user input
17
+ :param target_ext: target extension
18
+ :return: path to the input 3D model stored in target format.
19
+ """
20
+ path_input_base, ext = os.path.splitext(path_input)
21
+ if ext == "." + target_ext:
22
+ return path_input
23
+ path_output = path_input_base + "." + target_ext
24
+ if not os.path.exists(path_output):
25
+ trimesh.load_mesh(path_input).export(path_output)
26
+ return path_output
27
+
28
+
29
+ def add_lights(path_input, path_output):
30
+ glb = pygltflib.GLTF2().load(path_input)
31
+
32
+ N = 3 # default max num lights in Babylon.js is 4
33
+ angle_step = 2 * math.pi / N
34
+
35
+ lights_extension = {
36
+ "lights": [
37
+ {
38
+ "type": "directional",
39
+ "color": [1.0, 1.0, 1.0],
40
+ "intensity": 2.0
41
+ }
42
+ for _ in range(N)
43
+ ]
44
+ }
45
+
46
+ if "KHR_lights_punctual" not in glb.extensionsUsed:
47
+ glb.extensionsUsed.append("KHR_lights_punctual")
48
+ glb.extensions["KHR_lights_punctual"] = lights_extension
49
+
50
+ light_nodes = []
51
+ for i in range(N):
52
+ angle = i * angle_step
53
+ rotation = [
54
+ 0.0,
55
+ math.sin(angle / 2),
56
+ 0.0,
57
+ math.cos(angle / 2)
58
+ ]
59
+ node = {
60
+ "rotation": rotation,
61
+ "extensions": {
62
+ "KHR_lights_punctual": {
63
+ "light": i
64
+ }
65
+ }
66
+ }
67
+ light_nodes.append(node)
68
+
69
+ light_node_indices = list(range(len(glb.nodes), len(glb.nodes) + N))
70
+ glb.nodes.extend(light_nodes)
71
+
72
+ root_node_index = glb.scenes[glb.scene].nodes[0]
73
+ root_node = glb.nodes[root_node_index]
74
+ if hasattr(root_node, 'children'):
75
+ root_node.children.extend(light_node_indices)
76
+ else:
77
+ root_node.children = light_node_indices
78
+
79
+ glb.save(path_output)
80
+
81
+
82
+ class Model3D(gr.Model3D):
83
+ """
84
+ A simple overload of Gradio Model3D that accepts arbitrary 3D formats supported by trimesh.
85
+ """
86
+
87
+ def postprocess(self, y: str | Path | None) -> dict[str, str] | None:
88
+ if y is not None:
89
+ y = convert_formats(y, "glb")
90
+ out = super().postprocess(y)
91
+ return out
92
+
93
+
94
+ def breathe_new_life_into_3d_model(path_input, prompt):
95
+ """
96
+ @inproceedings{wang2023breathing,
97
+ title={Breathing New Life into 3D Assets with Generative Repainting},
98
+ author={Wang, Tianfu and Kanakis, Menelaos and Schindler, Konrad and Van Gool, Luc and Obukhov, Anton},
99
+ booktitle={Proceedings of the British Machine Vision Conference (BMVC)},
100
+ year={2023},
101
+ publisher={BMVA Press}
102
+ }
103
+ """
104
+ path_output_dir = path_input + ".output"
105
+ os.makedirs(path_output_dir, exist_ok=True)
106
+
107
+ path_input_ply = convert_formats(path_input, "ply")
108
+
109
+ cmd = [
110
+ "bash",
111
+ "/repainting_3d_assets/code/scripts/conda_run.sh",
112
+ "/repainting_3d_assets",
113
+ path_input_ply,
114
+ path_output_dir,
115
+ prompt,
116
+ ]
117
+ result = subprocess.run(cmd, env=os.environ, text=True)
118
+
119
+ if result.returncode != 0:
120
+ print(f"Output: {result.stdout}")
121
+ print(f"Stderr: {result.stderr}")
122
+ raise RuntimeError("Processing failed")
123
+
124
+ path_output_glb = os.path.join(path_output_dir, "model_draco.glb")
125
+ path_output_glb_vis = path_output_glb[:-4] + "_vis.glb"
126
+ add_lights(path_output_glb, path_output_glb_vis)
127
+
128
+ return path_output_glb_vis
129
+
130
+
131
+ def run():
132
+ desc = """
133
+ <p align="center">
134
+ <a title="Website" href="https://www.obukhov.ai/repainting_3d_assets" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
135
+ <img src="https://www.obukhov.ai/img/badges/badge-website.svg">
136
+ </a>
137
+ <a title="arXiv" href="https://arxiv.org/abs/2309.08523" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
138
+ <img src="https://www.obukhov.ai/img/badges/badge-pdf.svg">
139
+ </a>
140
+ <a title="Github" href="https://github.com/kongdai123/repainting_3d_assets" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
141
+ <img src="https://img.shields.io/github/stars/kongdai123/repainting_3d_assets?label=GitHub%20%E2%98%85&logo=github&color=C8C" alt="badge-github-stars">
142
+ </a>
143
+ <a title="Social" href="https://twitter.com/antonobukhov1" target="_blank" rel="noopener noreferrer" style="display: inline-block;">
144
+ <img src="https://www.obukhov.ai/img/badges/badge-social.svg" alt="social">
145
+ </a>
146
+ </p>
147
+ <p align="justify">
148
+ Repaint your 3D models with a text prompt, guided by a method from our BMVC'2023 Oral paper 'Breathing New Life
149
+ into 3D Assets with Generative Repainting'. Simply drop a model into the left pane, specify your repainting
150
+ preferences, and wait for the outcome (~20 min). Explore precomputed examples at the bottom, or follow the
151
+ Project Website badge for additional precomputed models and comparison with other repainting techniques.
152
+ </p>
153
+ """
154
+ demo = gr.Interface(
155
+ title="Repainting 3D Assets",
156
+ description=desc,
157
+ thumbnail="thumbnail.jpg",
158
+ fn=breathe_new_life_into_3d_model,
159
+ inputs=[
160
+ Model3D(
161
+ camera_position=(30.0, 90.0, 3.0),
162
+ elem_classes="viewport",
163
+ label="Input Model",
164
+ ),
165
+ gr.Textbox(label="Text Prompt"),
166
+ ],
167
+ outputs=[
168
+ gr.Model3D(
169
+ camera_position=(30.0, 90.0, 3.0),
170
+ elem_classes="viewport",
171
+ label="Repainted Model",
172
+ ),
173
+ ],
174
+ examples=[
175
+ [
176
+ os.path.join(os.path.dirname(__file__), "files/horse.ply"),
177
+ "pastel superhero unicorn",
178
+ ],
179
+ ],
180
+ cache_examples=True,
181
+ css="""
182
+ .viewport {
183
+ aspect-ratio: 16/9;
184
+ }
185
+ """,
186
+ allow_flagging="never",
187
+ )
188
+
189
+ demo.queue().launch(server_name="0.0.0.0", server_port=7860)
190
+
191
+
192
+ if __name__ == "__main__":
193
+ run()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ pygltflib
3
+ trimesh
thumbnail.jpg ADDED