Spaces:
Running
on
Zero
Running
on
Zero
xinjie.wang
commited on
Commit
·
bff3a5c
1
Parent(s):
b03efcd
update
Browse files- app.py +2 -2
- assets/example_texture/text_prompts.txt +3 -8
- embodied_gen/data/backproject_v2.py +18 -3
- embodied_gen/data/utils.py +13 -0
- embodied_gen/scripts/imageto3d.py +118 -115
- embodied_gen/scripts/texture_gen.sh +12 -1
app.py
CHANGED
|
@@ -61,7 +61,7 @@ with gr.Blocks(delete_cache=(43200, 43200), theme=custom_theme) as demo:
|
|
| 61 |
<a href="https://arxiv.org/abs/xxxx.xxxxx">
|
| 62 |
<img alt="📄 arXiv" src="https://img.shields.io/badge/📄-arXiv-b31b1b">
|
| 63 |
</a>
|
| 64 |
-
<a href="https://github.com/
|
| 65 |
<img alt="💻 GitHub" src="https://img.shields.io/badge/GitHub-000000?logo=github">
|
| 66 |
</a>
|
| 67 |
<a href="https://www.youtube.com/watch?v=SnHhzHeb_aI">
|
|
@@ -77,7 +77,7 @@ with gr.Blocks(delete_cache=(43200, 43200), theme=custom_theme) as demo:
|
|
| 77 |
elem_classes=["header"],
|
| 78 |
)
|
| 79 |
gr.HTML(image_css)
|
| 80 |
-
gr.HTML(lighting_css)
|
| 81 |
with gr.Row():
|
| 82 |
with gr.Column(scale=1):
|
| 83 |
mesh_input = gr.Model3D(
|
|
|
|
| 61 |
<a href="https://arxiv.org/abs/xxxx.xxxxx">
|
| 62 |
<img alt="📄 arXiv" src="https://img.shields.io/badge/📄-arXiv-b31b1b">
|
| 63 |
</a>
|
| 64 |
+
<a href="https://github.com/HorizonRobotics/EmbodiedGen">
|
| 65 |
<img alt="💻 GitHub" src="https://img.shields.io/badge/GitHub-000000?logo=github">
|
| 66 |
</a>
|
| 67 |
<a href="https://www.youtube.com/watch?v=SnHhzHeb_aI">
|
|
|
|
| 77 |
elem_classes=["header"],
|
| 78 |
)
|
| 79 |
gr.HTML(image_css)
|
| 80 |
+
# gr.HTML(lighting_css)
|
| 81 |
with gr.Row():
|
| 82 |
with gr.Column(scale=1):
|
| 83 |
mesh_input = gr.Model3D(
|
assets/example_texture/text_prompts.txt
CHANGED
|
@@ -1,28 +1,23 @@
|
|
| 1 |
assets/example_texture/meshes/robot.obj \ 写实风格机甲3D模型,主体色调为米色和深灰色,机甲结构带有机械细节和磨损痕迹
|
| 2 |
assets/example_texture/meshes/robot.obj \ 写实风格机甲3D模型,主体色调为深灰色和荧光黄,机甲结构带有机械细节和磨损痕迹
|
| 3 |
-
assets/example_texture/meshes/robot_text.obj \
|
| 4 |
-
assets/example_texture/meshes/robot_text.obj \
|
| 5 |
assets/example_texture/meshes/robot_text.obj \ 举着木质牌子的写实风格机甲3D模型,主体红色,牌子上写着“中国”的文字
|
| 6 |
-
assets/example_texture/meshes/robot_text.obj \
|
| 7 |
assets/example_texture/meshes/horse.obj \ 具有古典质感、鬃毛飞扬的棕色马首,黑色眼睛
|
| 8 |
assets/example_texture/meshes/horse.obj \ 具有古典质感、鬃毛飞扬的栗色马首
|
| 9 |
assets/example_texture/meshes/electric_drill.obj \ 电动手钻,有磨损细节,灰色红色相间磨砂质感哑光外壳
|
| 10 |
assets/example_texture/meshes/electric_drill.obj \ 电动手钻,有磨损细节,黄蓝色哑光外壳带有磨砂质感
|
| 11 |
assets/example_texture/meshes/chair.obj \ 具有大理石材质框架,坐垫为柔软青色织物纹理的旋转吧台椅
|
| 12 |
assets/example_texture/meshes/chair.obj \ 具有桃木色木质框架,坐垫为柔软灰色织物纹理的旋转吧台椅
|
| 13 |
-
assets/example_texture/meshes/table.obj \ 深棕色实木纹理的长桌,搭配六把现代灰色高脚凳
|
| 14 |
-
assets/example_texture/meshes/table.obj \ 现代大理石长桌,搭配六把实木棕色高脚凳
|
| 15 |
assets/example_texture/meshes/vase.obj \ 瓶身上绘有彩色飞鸟图案的花瓶
|
| 16 |
assets/example_texture/meshes/vase.obj \ 陶土花瓶
|
| 17 |
assets/example_texture/meshes/globe.obj \ 木质底座的经纬线地球仪
|
| 18 |
assets/example_texture/meshes/flashlight.obj \ 筒橡胶防滑纹路,红色磨砂质感的手电筒
|
| 19 |
assets/example_texture/meshes/bed.obj \ 简约现代风格的双人床,铺着灰色被子,上面摆放着几个红色的抱枕
|
| 20 |
assets/example_texture/meshes/bed.obj \ 北欧风格的双人床,浅灰色床单上面摆放着几个紫色的抱枕
|
| 21 |
-
assets/example_texture/meshes/cup.obj \ 带有立体花卉和蝴蝶结浮雕图案的陶瓷杯纹理,色调为复古暗色系
|
| 22 |
assets/example_texture/meshes/desk.obj \ 欧式风格木质梳妆台及配套凳子
|
| 23 |
assets/example_texture/meshes/desk.obj \ 白色带抽屉和镜子的欧式风格梳妆台及配套凳子模型,添加金色装饰细节
|
| 24 |
-
assets/example_texture/meshes/piano.obj \ 全身漆黑色立式钢琴及其配套棕色琴凳
|
| 25 |
-
assets/example_texture/meshes/piano.obj \ 白色立式钢琴及其紫色配套琴凳
|
| 26 |
assets/example_texture/meshes/clock.obj \ 木质闹钟,黑色指针,显示时间为数字
|
| 27 |
assets/example_texture/meshes/clock.obj \ 黑色闹钟搭配复古罗马数字表盘,古典韵味
|
| 28 |
assets/example_texture/meshes/table2.obj \ 一套现代简约风格的灰色方桌和四把木质椅子,桌面呈现光滑的哑光质感
|
|
|
|
| 1 |
assets/example_texture/meshes/robot.obj \ 写实风格机甲3D模型,主体色调为米色和深灰色,机甲结构带有机械细节和磨损痕迹
|
| 2 |
assets/example_texture/meshes/robot.obj \ 写实风格机甲3D模型,主体色调为深灰色和荧光黄,机甲结构带有机械细节和磨损痕迹
|
| 3 |
+
assets/example_texture/meshes/robot_text.obj \ 举着牌子的红色写实风格机器人,牌子上写着“Hello”的文字
|
| 4 |
+
assets/example_texture/meshes/robot_text.obj \ 举着牌子的彩色写实风格机器人,牌子上写着“World”的文字
|
| 5 |
assets/example_texture/meshes/robot_text.obj \ 举着木质牌子的写实风格机甲3D模型,主体红色,牌子上写着“中国”的文字
|
| 6 |
+
assets/example_texture/meshes/robot_text.obj \ 举着牌子的黄色写实风格机器人,牌子上画着爱心
|
| 7 |
assets/example_texture/meshes/horse.obj \ 具有古典质感、鬃毛飞扬的棕色马首,黑色眼睛
|
| 8 |
assets/example_texture/meshes/horse.obj \ 具有古典质感、鬃毛飞扬的栗色马首
|
| 9 |
assets/example_texture/meshes/electric_drill.obj \ 电动手钻,有磨损细节,灰色红色相间磨砂质感哑光外壳
|
| 10 |
assets/example_texture/meshes/electric_drill.obj \ 电动手钻,有磨损细节,黄蓝色哑光外壳带有磨砂质感
|
| 11 |
assets/example_texture/meshes/chair.obj \ 具有大理石材质框架,坐垫为柔软青色织物纹理的旋转吧台椅
|
| 12 |
assets/example_texture/meshes/chair.obj \ 具有桃木色木质框架,坐垫为柔软灰色织物纹理的旋转吧台椅
|
|
|
|
|
|
|
| 13 |
assets/example_texture/meshes/vase.obj \ 瓶身上绘有彩色飞鸟图案的花瓶
|
| 14 |
assets/example_texture/meshes/vase.obj \ 陶土花瓶
|
| 15 |
assets/example_texture/meshes/globe.obj \ 木质底座的经纬线地球仪
|
| 16 |
assets/example_texture/meshes/flashlight.obj \ 筒橡胶防滑纹路,红色磨砂质感的手电筒
|
| 17 |
assets/example_texture/meshes/bed.obj \ 简约现代风格的双人床,铺着灰色被子,上面摆放着几个红色的抱枕
|
| 18 |
assets/example_texture/meshes/bed.obj \ 北欧风格的双人床,浅灰色床单上面摆放着几个紫色的抱枕
|
|
|
|
| 19 |
assets/example_texture/meshes/desk.obj \ 欧式风格木质梳妆台及配套凳子
|
| 20 |
assets/example_texture/meshes/desk.obj \ 白色带抽屉和镜子的欧式风格梳妆台及配套凳子模型,添加金色装饰细节
|
|
|
|
|
|
|
| 21 |
assets/example_texture/meshes/clock.obj \ 木质闹钟,黑色指针,显示时间为数字
|
| 22 |
assets/example_texture/meshes/clock.obj \ 黑色闹钟搭配复古罗马数字表盘,古典韵味
|
| 23 |
assets/example_texture/meshes/table2.obj \ 一套现代简约风格的灰色方桌和四把木质椅子,桌面呈现光滑的哑光质感
|
embodied_gen/data/backproject_v2.py
CHANGED
|
@@ -606,7 +606,17 @@ def parse_args():
|
|
| 606 |
"--delight", action="store_true", help="Use delighting model."
|
| 607 |
)
|
| 608 |
parser.add_argument(
|
| 609 |
-
"--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
)
|
| 611 |
|
| 612 |
args, unknown = parser.parse_known_args()
|
|
@@ -642,7 +652,8 @@ def entrypoint(
|
|
| 642 |
save_dir = os.path.dirname(args.output_path)
|
| 643 |
os.makedirs(save_dir, exist_ok=True)
|
| 644 |
color_grid = delight_model(color_grid)
|
| 645 |
-
|
|
|
|
| 646 |
|
| 647 |
multiviews = get_images_from_grid(color_grid, img_size=512)
|
| 648 |
|
|
@@ -675,11 +686,15 @@ def entrypoint(
|
|
| 675 |
view_weights=view_weights,
|
| 676 |
render_wh=camera_params.resolution_hw,
|
| 677 |
texture_wh=args.texture_wh,
|
| 678 |
-
smooth_texture=args.
|
| 679 |
)
|
| 680 |
|
| 681 |
textured_mesh = texture_backer(multiviews, mesh, args.output_path)
|
| 682 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
return textured_mesh
|
| 684 |
|
| 685 |
|
|
|
|
| 606 |
"--delight", action="store_true", help="Use delighting model."
|
| 607 |
)
|
| 608 |
parser.add_argument(
|
| 609 |
+
"--no_smooth_texture",
|
| 610 |
+
action="store_true",
|
| 611 |
+
help="Do not smooth the texture.",
|
| 612 |
+
)
|
| 613 |
+
parser.add_argument(
|
| 614 |
+
"--save_glb_path", type=str, default=None, help="Save glb path."
|
| 615 |
+
)
|
| 616 |
+
parser.add_argument(
|
| 617 |
+
"--no_save_delight_img",
|
| 618 |
+
action="store_true",
|
| 619 |
+
help="Disable saving delight image",
|
| 620 |
)
|
| 621 |
|
| 622 |
args, unknown = parser.parse_known_args()
|
|
|
|
| 652 |
save_dir = os.path.dirname(args.output_path)
|
| 653 |
os.makedirs(save_dir, exist_ok=True)
|
| 654 |
color_grid = delight_model(color_grid)
|
| 655 |
+
if not args.no_save_delight_img:
|
| 656 |
+
color_grid.save(f"{save_dir}/color_grid_delight.png")
|
| 657 |
|
| 658 |
multiviews = get_images_from_grid(color_grid, img_size=512)
|
| 659 |
|
|
|
|
| 686 |
view_weights=view_weights,
|
| 687 |
render_wh=camera_params.resolution_hw,
|
| 688 |
texture_wh=args.texture_wh,
|
| 689 |
+
smooth_texture=not args.no_smooth_texture,
|
| 690 |
)
|
| 691 |
|
| 692 |
textured_mesh = texture_backer(multiviews, mesh, args.output_path)
|
| 693 |
|
| 694 |
+
if args.save_glb_path is not None:
|
| 695 |
+
os.makedirs(os.path.dirname(args.save_glb_path), exist_ok=True)
|
| 696 |
+
textured_mesh.export(args.save_glb_path)
|
| 697 |
+
|
| 698 |
return textured_mesh
|
| 699 |
|
| 700 |
|
embodied_gen/data/utils.py
CHANGED
|
@@ -19,6 +19,7 @@ import math
|
|
| 19 |
import os
|
| 20 |
import random
|
| 21 |
import zipfile
|
|
|
|
| 22 |
from typing import List, Tuple, Union
|
| 23 |
|
| 24 |
import cv2
|
|
@@ -66,6 +67,7 @@ __all__ = [
|
|
| 66 |
"gamma_shs",
|
| 67 |
"resize_pil",
|
| 68 |
"trellis_preprocess",
|
|
|
|
| 69 |
]
|
| 70 |
|
| 71 |
|
|
@@ -994,3 +996,14 @@ def zip_files(input_paths: list[str], output_zip: str) -> str:
|
|
| 994 |
zipf.write(input_path, arcname=arcname)
|
| 995 |
|
| 996 |
return output_zip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
import os
|
| 20 |
import random
|
| 21 |
import zipfile
|
| 22 |
+
from shutil import rmtree
|
| 23 |
from typing import List, Tuple, Union
|
| 24 |
|
| 25 |
import cv2
|
|
|
|
| 67 |
"gamma_shs",
|
| 68 |
"resize_pil",
|
| 69 |
"trellis_preprocess",
|
| 70 |
+
"delete_dir",
|
| 71 |
]
|
| 72 |
|
| 73 |
|
|
|
|
| 996 |
zipf.write(input_path, arcname=arcname)
|
| 997 |
|
| 998 |
return output_zip
|
| 999 |
+
|
| 1000 |
+
|
| 1001 |
+
def delete_dir(folder_path: str, keep_subs: list[str] = None) -> None:
|
| 1002 |
+
for item in os.listdir(folder_path):
|
| 1003 |
+
if keep_subs is not None and item in keep_subs:
|
| 1004 |
+
continue
|
| 1005 |
+
item_path = os.path.join(folder_path, item)
|
| 1006 |
+
if os.path.isdir(item_path):
|
| 1007 |
+
rmtree(item_path)
|
| 1008 |
+
else:
|
| 1009 |
+
os.remove(item_path)
|
embodied_gen/scripts/imageto3d.py
CHANGED
|
@@ -20,12 +20,13 @@ import logging
|
|
| 20 |
import os
|
| 21 |
import sys
|
| 22 |
from glob import glob
|
|
|
|
| 23 |
|
| 24 |
import numpy as np
|
| 25 |
import trimesh
|
| 26 |
from PIL import Image
|
| 27 |
from embodied_gen.data.backproject_v2 import entrypoint as backproject_api
|
| 28 |
-
from embodied_gen.data.utils import trellis_preprocess
|
| 29 |
from embodied_gen.models.delight_model import DelightingModel
|
| 30 |
from embodied_gen.models.gs_model import GaussianOperator
|
| 31 |
from embodied_gen.models.segment_model import (
|
|
@@ -97,9 +98,6 @@ def parse_args():
|
|
| 97 |
required=True,
|
| 98 |
help="Root directory for saving outputs.",
|
| 99 |
)
|
| 100 |
-
parser.add_argument(
|
| 101 |
-
"--no_mesh", action="store_true", help="Do not output mesh files."
|
| 102 |
-
)
|
| 103 |
parser.add_argument(
|
| 104 |
"--height_range",
|
| 105 |
type=str,
|
|
@@ -116,6 +114,7 @@ def parse_args():
|
|
| 116 |
parser.add_argument("--skip_exists", action="store_true")
|
| 117 |
parser.add_argument("--strict_seg", action="store_true")
|
| 118 |
parser.add_argument("--version", type=str, default=VERSION)
|
|
|
|
| 119 |
args = parser.parse_args()
|
| 120 |
|
| 121 |
assert (
|
|
@@ -136,7 +135,7 @@ if __name__ == "__main__":
|
|
| 136 |
try:
|
| 137 |
filename = os.path.basename(image_path).split(".")[0]
|
| 138 |
output_root = args.output_root
|
| 139 |
-
if args.image_root is not None:
|
| 140 |
output_root = os.path.join(output_root, filename)
|
| 141 |
os.makedirs(output_root, exist_ok=True)
|
| 142 |
|
|
@@ -189,117 +188,121 @@ if __name__ == "__main__":
|
|
| 189 |
video_path = os.path.join(output_root, "gs_mesh.mp4")
|
| 190 |
merge_images_video(color_images, normal_images, video_path)
|
| 191 |
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
)
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
asset_attrs =
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
images = [
|
| 296 |
-
f"{output_root}/{filename}_raw.png",
|
| 297 |
-
f"{output_root}/{filename}_cond.png",
|
| 298 |
-
]
|
| 299 |
-
images_list.append(images)
|
| 300 |
-
|
| 301 |
-
results = BaseChecker.validate(CHECKERS, images_list)
|
| 302 |
-
urdf_convertor.add_quality_tag(urdf_path, results)
|
| 303 |
|
| 304 |
except Exception as e:
|
| 305 |
logger.error(f"Failed to process {image_path}: {e}, skip.")
|
|
|
|
| 20 |
import os
|
| 21 |
import sys
|
| 22 |
from glob import glob
|
| 23 |
+
from shutil import copy, copytree
|
| 24 |
|
| 25 |
import numpy as np
|
| 26 |
import trimesh
|
| 27 |
from PIL import Image
|
| 28 |
from embodied_gen.data.backproject_v2 import entrypoint as backproject_api
|
| 29 |
+
from embodied_gen.data.utils import delete_dir, trellis_preprocess
|
| 30 |
from embodied_gen.models.delight_model import DelightingModel
|
| 31 |
from embodied_gen.models.gs_model import GaussianOperator
|
| 32 |
from embodied_gen.models.segment_model import (
|
|
|
|
| 98 |
required=True,
|
| 99 |
help="Root directory for saving outputs.",
|
| 100 |
)
|
|
|
|
|
|
|
|
|
|
| 101 |
parser.add_argument(
|
| 102 |
"--height_range",
|
| 103 |
type=str,
|
|
|
|
| 114 |
parser.add_argument("--skip_exists", action="store_true")
|
| 115 |
parser.add_argument("--strict_seg", action="store_true")
|
| 116 |
parser.add_argument("--version", type=str, default=VERSION)
|
| 117 |
+
parser.add_argument("--remove_intermediate", type=bool, default=True)
|
| 118 |
args = parser.parse_args()
|
| 119 |
|
| 120 |
assert (
|
|
|
|
| 135 |
try:
|
| 136 |
filename = os.path.basename(image_path).split(".")[0]
|
| 137 |
output_root = args.output_root
|
| 138 |
+
if args.image_root is not None or len(args.image_path) > 1:
|
| 139 |
output_root = os.path.join(output_root, filename)
|
| 140 |
os.makedirs(output_root, exist_ok=True)
|
| 141 |
|
|
|
|
| 188 |
video_path = os.path.join(output_root, "gs_mesh.mp4")
|
| 189 |
merge_images_video(color_images, normal_images, video_path)
|
| 190 |
|
| 191 |
+
# Save the raw Gaussian model
|
| 192 |
+
gs_path = mesh_out.replace(".obj", "_gs.ply")
|
| 193 |
+
gs_model.save_ply(gs_path)
|
| 194 |
+
|
| 195 |
+
# Rotate mesh and GS by 90 degrees around Z-axis.
|
| 196 |
+
rot_matrix = [[0, 0, -1], [0, 1, 0], [1, 0, 0]]
|
| 197 |
+
gs_add_rot = [[1, 0, 0], [0, -1, 0], [0, 0, -1]]
|
| 198 |
+
mesh_add_rot = [[1, 0, 0], [0, 0, -1], [0, 1, 0]]
|
| 199 |
+
|
| 200 |
+
# Addtional rotation for GS to align mesh.
|
| 201 |
+
gs_rot = np.array(gs_add_rot) @ np.array(rot_matrix)
|
| 202 |
+
pose = GaussianOperator.trans_to_quatpose(gs_rot)
|
| 203 |
+
aligned_gs_path = gs_path.replace(".ply", "_aligned.ply")
|
| 204 |
+
GaussianOperator.resave_ply(
|
| 205 |
+
in_ply=gs_path,
|
| 206 |
+
out_ply=aligned_gs_path,
|
| 207 |
+
instance_pose=pose,
|
| 208 |
+
device="cpu",
|
| 209 |
+
)
|
| 210 |
+
color_path = os.path.join(output_root, "color.png")
|
| 211 |
+
render_gs_api(aligned_gs_path, color_path)
|
| 212 |
+
|
| 213 |
+
mesh = trimesh.Trimesh(
|
| 214 |
+
vertices=mesh_model.vertices.cpu().numpy(),
|
| 215 |
+
faces=mesh_model.faces.cpu().numpy(),
|
| 216 |
+
)
|
| 217 |
+
mesh.vertices = mesh.vertices @ np.array(mesh_add_rot)
|
| 218 |
+
mesh.vertices = mesh.vertices @ np.array(rot_matrix)
|
| 219 |
+
|
| 220 |
+
mesh_obj_path = os.path.join(output_root, f"{filename}.obj")
|
| 221 |
+
mesh.export(mesh_obj_path)
|
| 222 |
+
|
| 223 |
+
mesh = backproject_api(
|
| 224 |
+
delight_model=DELIGHT,
|
| 225 |
+
imagesr_model=IMAGESR_MODEL,
|
| 226 |
+
color_path=color_path,
|
| 227 |
+
mesh_path=mesh_obj_path,
|
| 228 |
+
output_path=mesh_obj_path,
|
| 229 |
+
skip_fix_mesh=False,
|
| 230 |
+
delight=True,
|
| 231 |
+
texture_wh=[2048, 2048],
|
| 232 |
+
)
|
| 233 |
+
|
| 234 |
+
mesh_glb_path = os.path.join(output_root, f"{filename}.glb")
|
| 235 |
+
mesh.export(mesh_glb_path)
|
| 236 |
+
|
| 237 |
+
urdf_convertor = URDFGenerator(GPT_CLIENT, render_view_num=4)
|
| 238 |
+
asset_attrs = {
|
| 239 |
+
"version": VERSION,
|
| 240 |
+
"gs_model": f"{urdf_convertor.output_mesh_dir}/{filename}_gs.ply",
|
| 241 |
+
}
|
| 242 |
+
if args.height_range:
|
| 243 |
+
min_height, max_height = map(
|
| 244 |
+
float, args.height_range.split("-")
|
| 245 |
)
|
| 246 |
+
asset_attrs["min_height"] = min_height
|
| 247 |
+
asset_attrs["max_height"] = max_height
|
| 248 |
+
if args.mass_range:
|
| 249 |
+
min_mass, max_mass = map(float, args.mass_range.split("-"))
|
| 250 |
+
asset_attrs["min_mass"] = min_mass
|
| 251 |
+
asset_attrs["max_mass"] = max_mass
|
| 252 |
+
if args.asset_type:
|
| 253 |
+
asset_attrs["category"] = args.asset_type
|
| 254 |
+
if args.version:
|
| 255 |
+
asset_attrs["version"] = args.version
|
| 256 |
+
|
| 257 |
+
urdf_root = f"{output_root}/URDF_{filename}"
|
| 258 |
+
urdf_path = urdf_convertor(
|
| 259 |
+
mesh_path=mesh_obj_path,
|
| 260 |
+
output_root=urdf_root,
|
| 261 |
+
**asset_attrs,
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
# Rescale GS and save to URDF/mesh folder.
|
| 265 |
+
real_height = urdf_convertor.get_attr_from_urdf(
|
| 266 |
+
urdf_path, attr_name="real_height"
|
| 267 |
+
)
|
| 268 |
+
out_gs = f"{urdf_root}/{urdf_convertor.output_mesh_dir}/{filename}_gs.ply" # noqa
|
| 269 |
+
GaussianOperator.resave_ply(
|
| 270 |
+
in_ply=aligned_gs_path,
|
| 271 |
+
out_ply=out_gs,
|
| 272 |
+
real_height=real_height,
|
| 273 |
+
device="cpu",
|
| 274 |
+
)
|
| 275 |
+
|
| 276 |
+
# Quality check and update .urdf file.
|
| 277 |
+
mesh_out = f"{urdf_root}/{urdf_convertor.output_mesh_dir}/{filename}.obj" # noqa
|
| 278 |
+
trimesh.load(mesh_out).export(mesh_out.replace(".obj", ".glb"))
|
| 279 |
+
|
| 280 |
+
image_dir = f"{urdf_root}/{urdf_convertor.output_render_dir}/image_color" # noqa
|
| 281 |
+
image_paths = glob(f"{image_dir}/*.png")
|
| 282 |
+
images_list = []
|
| 283 |
+
for checker in CHECKERS:
|
| 284 |
+
images = image_paths
|
| 285 |
+
if isinstance(checker, ImageSegChecker):
|
| 286 |
+
images = [
|
| 287 |
+
f"{output_root}/{filename}_raw.png",
|
| 288 |
+
f"{output_root}/{filename}_cond.png",
|
| 289 |
+
]
|
| 290 |
+
images_list.append(images)
|
| 291 |
+
|
| 292 |
+
results = BaseChecker.validate(CHECKERS, images_list)
|
| 293 |
+
urdf_convertor.add_quality_tag(urdf_path, results)
|
| 294 |
+
|
| 295 |
+
# Organize the final result files
|
| 296 |
+
result_dir = f"{output_root}/result"
|
| 297 |
+
os.makedirs(result_dir, exist_ok=True)
|
| 298 |
+
copy(urdf_path, f"{result_dir}/{os.path.basename(urdf_path)}")
|
| 299 |
+
copytree(
|
| 300 |
+
f"{urdf_root}/{urdf_convertor.output_mesh_dir}",
|
| 301 |
+
f"{result_dir}/{urdf_convertor.output_mesh_dir}",
|
| 302 |
+
)
|
| 303 |
+
copy(video_path, f"{result_dir}/video.mp4")
|
| 304 |
+
if args.remove_intermediate:
|
| 305 |
+
delete_dir(output_root, keep_subs=["result"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 306 |
|
| 307 |
except Exception as e:
|
| 308 |
logger.error(f"Failed to process {image_path}: {e}, skip.")
|
embodied_gen/scripts/texture_gen.sh
CHANGED
|
@@ -56,8 +56,10 @@ python embodied_gen/scripts/render_mv.py \
|
|
| 56 |
backproject-cli --mesh_path ${mesh_path} \
|
| 57 |
--color_path ${output_root}/multi_view/color_sample0.png \
|
| 58 |
--output_path "${output_root}/texture_mesh/${uuid}.obj" \
|
|
|
|
| 59 |
--skip_fix_mesh \
|
| 60 |
-
--delight
|
|
|
|
| 61 |
|
| 62 |
# Step 4: final rendering of textured mesh
|
| 63 |
drender-cli --mesh_path "${output_root}/texture_mesh/${uuid}.obj" \
|
|
@@ -67,3 +69,12 @@ drender-cli --mesh_path "${output_root}/texture_mesh/${uuid}.obj" \
|
|
| 67 |
--with_mtl \
|
| 68 |
--gen_color_mp4 \
|
| 69 |
--pbr_light_factor 1.2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
backproject-cli --mesh_path ${mesh_path} \
|
| 57 |
--color_path ${output_root}/multi_view/color_sample0.png \
|
| 58 |
--output_path "${output_root}/texture_mesh/${uuid}.obj" \
|
| 59 |
+
--save_glb_path "${output_root}/texture_mesh/${uuid}.glb" \
|
| 60 |
--skip_fix_mesh \
|
| 61 |
+
--delight \
|
| 62 |
+
--no_save_delight_img
|
| 63 |
|
| 64 |
# Step 4: final rendering of textured mesh
|
| 65 |
drender-cli --mesh_path "${output_root}/texture_mesh/${uuid}.obj" \
|
|
|
|
| 69 |
--with_mtl \
|
| 70 |
--gen_color_mp4 \
|
| 71 |
--pbr_light_factor 1.2
|
| 72 |
+
|
| 73 |
+
# Organize folders
|
| 74 |
+
rm -rf ${output_root}/condition
|
| 75 |
+
video_path="${output_root}/texture_mesh/${uuid}/color.mp4"
|
| 76 |
+
if [ -f "${video_path}" ]; then
|
| 77 |
+
cp "${video_path}" "${output_root}/texture_mesh/color.mp4"
|
| 78 |
+
echo "Resave video to ${output_root}/texture_mesh/color.mp4"
|
| 79 |
+
fi
|
| 80 |
+
rm -rf ${output_root}/texture_mesh/${uuid}
|