adsfda commited on
Commit
615ac66
·
1 Parent(s): 6008f32

feat: p test func

Browse files
Files changed (2) hide show
  1. app.py +145 -72
  2. requirements.txt +2 -1
app.py CHANGED
@@ -1,86 +1,159 @@
1
  import gradio as gr
2
- import pytexrecon
3
- import os
 
 
 
4
 
5
- def process_texturing(mesh_file, image_files, intrinsics_text, pose_texts):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  try:
7
- # 初始化TexRecon
8
- tex = pytexrecon.TexRecon(verbose=True)
9
-
10
- # 处理输入数据
11
- with open(mesh_file.name, "rb") as f:
12
- mesh_data = f.read()
13
-
14
- # 处理图像
15
- images = {}
16
- for img_file in image_files:
17
- img_name = os.path.basename(img_file.name)
18
- with open(img_file.name, "rb") as f:
19
- images[img_name] = f.read()
20
-
21
- # 处理姿态数据
22
- poses = {}
23
- for img_file, pose_text in zip(image_files, pose_texts):
24
- img_name = os.path.basename(img_file.name)
25
- poses[img_name] = pose_text
26
-
27
- # 运行纹理重建
28
- mesh_bytes, texture_bytes = tex.run_texturing(
29
  mesh_data=mesh_data,
30
  images=images,
31
- intrinsics=intrinsics_text,
32
  poses=poses,
33
- texture_resolution=2048,
34
  fill_holes=True
35
  )
36
-
37
- # 保存结果到临时文件
38
- with open("textured_mesh.obj", "wb") as f:
39
- f.write(mesh_bytes)
40
-
41
- with open("texture.png", "wb") as f:
42
- f.write(texture_bytes)
43
-
44
- return "textured_mesh.obj", "texture.png", "纹理重建功!"
45
-
 
 
 
 
46
  except Exception as e:
47
- return None, None, f"处理失败: {str(e)}"
 
 
 
 
 
 
 
 
48
 
49
- # 创建Gradio界面
50
- with gr.Blocks(title="TexRecon 纹理重建工具") as demo:
51
- gr.Markdown("# TexRecon 纹理重建工具")
52
- gr.Markdown("上传网格模型、图像序列和相机参数,生成带纹理的3D模型")
53
-
54
  with gr.Row():
55
- with gr.Column(scale=1):
56
- mesh_file = gr.File(label="网格 (.ply)", file_types=[".ply"])
57
- image_files = gr.File(label="图像序列", file_types=[".jpg", ".png"], file_count="multiple")
58
-
59
- intrinsics_text = gr.Textbox(
60
- label="相机内参",
61
- placeholder="输入相机内参数据",
62
- lines=5
63
- )
64
-
65
- pose_texts = gr.Textbox(
66
- label="相机姿态 (每个像一个)",
67
- placeholder="输入相机姿态数据,每个图像一行",
68
- lines=5
69
- )
70
-
71
- process_btn = gr.Button("开始纹理重建")
72
-
73
- with gr.Column(scale=1):
74
- output_mesh = gr.File(label="带纹理的模型")
75
- output_texture = gr.Image(label="纹贴图")
76
- status_text = gr.Textbox(label="状态")
77
-
78
- process_btn.click(
79
- fn=process_texturing,
80
- inputs=[mesh_file, image_files, intrinsics_text, pose_texts],
81
- outputs=[output_mesh, output_texture, status_text]
 
 
 
 
 
 
 
 
 
 
 
 
82
  )
83
 
 
 
84
  if __name__ == "__main__":
85
- demo.launch()
86
-
 
1
  import gradio as gr
2
+ import pytexrecon # 导入你之前的pytexrecon封装
3
+ import numpy as np
4
+ from PIL import Image
5
+ import io
6
+ from typing import Dict, Tuple, Optional
7
 
8
+
9
+ def generate_test_data() -> Tuple[bytes, Dict[str, bytes], str, Dict[str, str]]:
10
+ """
11
+ 生成TexRecon测试所需的模拟数据(无需真实上传):
12
+ 返回:(网格文件二进制, 图像字典, 内参字符串, 姿态字典)
13
+ """
14
+ # 1. 模拟网格数据:最小化PLY格式文件(一个三角形面,3个顶点)
15
+ ply_content = """ply
16
+ format ascii 1.0
17
+ element vertex 3
18
+ property float x
19
+ property float y
20
+ property float z
21
+ element face 1
22
+ property list uchar int vertex_indices
23
+ end_header
24
+ 0.0 0.0 0.0
25
+ 1.0 0.0 0.0
26
+ 0.5 1.0 0.0
27
+ 3 0 1 2
28
+ """
29
+ mesh_bytes = ply_content.encode("utf-8") # 转为二进制,符合pytexrecon输入要求
30
+
31
+ # 2. 模拟图像数据:2张64x64的纯色图像(红色+蓝色,避免空文件)
32
+ images: Dict[str, bytes] = {}
33
+ # 第一张图:红色
34
+ red_img = Image.new("RGB", (64, 64), color="red")
35
+ red_img_byteio = io.BytesIO()
36
+ red_img.save(red_img_byteio, format="PNG")
37
+ images["test1.png"] = red_img_byteio.getvalue()
38
+ # 第二张图:蓝色
39
+ blue_img = Image.new("RGB", (64, 64), color="blue")
40
+ blue_img_byteio = io.BytesIO()
41
+ blue_img.save(blue_img_byteio, format="PNG")
42
+ images["test2.png"] = blue_img_byteio.getvalue()
43
+
44
+ # 3. 模拟相机内参:简单针孔相机参数(适配64x64图像)
45
+ # 格式:相机ID fx fy cx cy k1 k2 p1 p2 (k1-k2为畸变系数,p1-p2为切向畸变,此处设为0)
46
+ intrinsics = "0 32.0 32.0 32.0 32.0 0.0 0.0 0.0 0.0"
47
+
48
+ # 4. 模拟相机姿态:2个图像对应的简单位姿(单位矩阵,代表相机在原点)
49
+ # 姿态格式:4x4齐次变换矩阵(每行用空格分隔,最后一行固定为0 0 0 1)
50
+ pose_matrix = """1.0 0.0 0.0 0.0
51
+ 0.0 1.0 0.0 0.0
52
+ 0.0 0.0 1.0 2.0 # 相机在z轴2m处,朝向原点
53
+ 0.0 0.0 0.0 1.0"""
54
+ poses: Dict[str, str] = {
55
+ "test1.png": pose_matrix, # 第一张图的姿态
56
+ "test2.png": pose_matrix # 第二张图的姿态(简化用同一姿态)
57
+ }
58
+
59
+ return mesh_bytes, images, intrinsics, poses
60
+
61
+
62
+ def test_texrecon_flow(verbose: bool = True) -> Tuple[str, Optional[bytes], Optional[bytes], Optional[Image.Image]]:
63
+ """
64
+ 完整测试pytexrecon流程:生成模拟数据 → 调用TexRecon → 返回结果
65
+ 返回:(测试状态, 带纹理模型二进制, 纹理图二进制, 纹理图PIL对象)
66
+ """
67
  try:
68
+ # 步骤1:生成模拟测试数据
69
+ if verbose:
70
+ print("=== 步骤1:生成模拟测试数据 ===")
71
+ mesh_data, images, intrinsics, poses = generate_test_data()
72
+
73
+ # 步骤2:初始化pytexrecon(自动检查/编译TexRecon)
74
+ if verbose:
75
+ print("=== 步骤2:初始化pytexrecon ===")
76
+ texrecon = pytexrecon.TexRecon(verbose=verbose)
77
+
78
+ # 步骤3:调用TexRecon纹理重建(核心测试)
79
+ if verbose:
80
+ print("=== 步骤3:调用TexRecon纹理重建 ===")
81
+ textured_mesh_bytes, texture_bytes = texrecon.run_texturing(
 
 
 
 
 
 
 
 
82
  mesh_data=mesh_data,
83
  images=images,
84
+ intrinsics=intrinsics,
85
  poses=poses,
86
+ texture_resolution=256, # 小分辨率加速测试
87
  fill_holes=True
88
  )
89
+
90
+ # 步骤4:处理纹理图(转为PIL对象,方便Gradio显示)
91
+ texture_img = Image.open(io.BytesIO(texture_bytes)) if texture_bytes else None
92
+
93
+ # 步骤5:返回成功结果
94
+ status = (
95
+ "✅ 全流程测试成功!\n"
96
+ "- TexRecon可执行文件正常(已找到/编译)\n"
97
+ "- 模拟数据生正常\n"
98
+ "- 纹理重建命令执行成功\n"
99
+ "- 已生成带纹理模型和纹理图"
100
+ )
101
+ return status, textured_mesh_bytes, texture_bytes, texture_img
102
+
103
  except Exception as e:
104
+ # 捕获所有异常,返回错误信息
105
+ status = f"❌ 测试失败:\n{str(e)}"
106
+ return status, None, None, None
107
+
108
+
109
+ # 构建Gradio界面:一键测试+结果展示
110
+ with gr.Blocks(title="pytexrecon 模拟测试工具") as demo:
111
+ gr.Markdown("# pytexrecon 全流程模拟测试")
112
+ gr.Markdown("无需上传真实数据,点击按钮即可测试封装是否正常工作(自动生成模拟数据)")
113
 
 
 
 
 
 
114
  with gr.Row():
115
+ # 测试按钮(点击触发全流程)
116
+ test_btn = gr.Button("🚀 开始拟测试", variant="primary", size="lg")
117
+
118
+ # 结果展示区域
119
+ with gr.Group():
120
+ gr.Markdown("### 测试状态")
121
+ status_box = gr.Textbox(label="状态日志", lines=5, interactive=False)
122
+
123
+ gr.Markdown("### 输出结果预览")
124
+ with gr.Row():
125
+ # 纹理图预览(可视化验证)
126
+ texture_preview = gr.Image(label="生成的纹理图", interactive=False)
127
+ # 带纹理模型下载(验证文件是否正常生成)
128
+ mesh_download = gr.File(label="下载带纹理模型(.obj)", interactive=False)
129
+ # 纹理图下载
130
+ texture_download = gr.File(label="下载纹理图(.png)", interactive=False)
131
+
132
+ # 绑定按钮事件:点击后跑测试,更新结果
133
+ def on_test_click():
134
+ status, mesh_bytes, texture_bytes, texture_img = test_texrecon_flow()
135
+ # 下载文件(Gradio需要文件路径或二进制+文件名)
136
+ mesh_file = gr.File.update(
137
+ value=mesh_bytes,
138
+ label="下载带纹理模型(.obj)",
139
+ file_name="test_textured_mesh.obj"
140
+ ) if mesh_bytes else gr.File.update(value=None, label="下载带纹理模型(.obj)")
141
+
142
+ texture_file = gr.File.update(
143
+ value=texture_bytes,
144
+ label="下载纹理图(.png)",
145
+ file_name="test_texture.png"
146
+ ) if texture_bytes else gr.File.update(value=None, label="下载纹理图(.png)")
147
+
148
+ return status, mesh_file, texture_file, texture_img
149
+
150
+ # 绑定点击事件(无输入,直接触发)
151
+ test_btn.click(
152
+ fn=on_test_click,
153
+ outputs=[status_box, mesh_download, texture_download, texture_preview]
154
  )
155
 
156
+
157
+ # 启动应用(适配Hugging Face Space,默认使用0.0.0.0地址)
158
  if __name__ == "__main__":
159
+ demo.launch(server_name="0.0.0.0", server_port=7860)
 
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
  gradio>=3.0
2
- numpy
 
3
 
 
1
  gradio>=3.0
2
+ pillow>=9.0
3
+ numpy>=1.21
4