File size: 6,393 Bytes
f813a93
744ff8d
615ac66
 
 
 
f813a93
615ac66
744ff8d
 
eca8afc
744ff8d
 
da98f58
 
 
 
 
 
744ff8d
 
 
eca8afc
744ff8d
 
615ac66
 
 
 
 
 
 
 
 
 
 
 
 
 
744ff8d
615ac66
744ff8d
615ac66
744ff8d
615ac66
744ff8d
 
 
 
615ac66
744ff8d
 
 
615ac66
744ff8d
eca8afc
615ac66
744ff8d
615ac66
 
744ff8d
615ac66
744ff8d
615ac66
 
 
 
744ff8d
eca8afc
744ff8d
 
f813a93
744ff8d
f813a93
 
615ac66
f813a93
eca8afc
f813a93
 
744ff8d
 
 
 
615ac66
 
744ff8d
 
eca8afc
744ff8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
615ac66
f813a93
615ac66
 
744ff8d
 
 
eca8afc
744ff8d
 
eca8afc
615ac66
eca8afc
744ff8d
f813a93
 
744ff8d
615ac66
eca8afc
615ac66
eca8afc
744ff8d
615ac66
eca8afc
 
744ff8d
eca8afc
615ac66
eca8afc
 
 
615ac66
eca8afc
615ac66
744ff8d
eca8afc
 
744ff8d
eca8afc
 
 
 
 
744ff8d
 
eca8afc
 
 
 
 
 
744ff8d
615ac66
eca8afc
615ac66
 
744ff8d
eca8afc
 
 
 
 
 
744ff8d
f813a93
 
615ac66
eca8afc
f813a93
eca8afc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import gradio as gr
import pytexrecon  # 导入你的pytexrecon封装
import numpy as np
from PIL import Image
import io
from typing import Dict, Tuple, Optional


# -------------------------- 核心功能:拆分步骤,优先验证TexRecon实例 --------------------------
def init_texrecon(verbose: bool = True) -> pytexrecon.TexRecon:
    """单独初始化TexRecon实例(优先验证核心依赖)"""
    if verbose:
        print("=== 步骤1/3:初始化TexRecon实例(优先验证) ===")
    
    texrecon_instance = pytexrecon.TexRecon(verbose=verbose)
    texrecon_instance._check_texrecon()
    return texrecon_instance

        


def generate_test_data() -> Tuple[bytes, Dict[str, bytes], str, Dict[str, str]]:
    """生成TexRecon测试所需的模拟数据"""
    print("=== 步骤2/3:生成模拟测试数据 ===")
    # 1. 模拟PLY网格(3个顶点+1个三角形面)
    ply_content = """ply
format ascii 1.0
element vertex 3
property float x
property float y
property float z
element face 1
property list uchar int vertex_indices
end_header
0.0 0.0 0.0
1.0 0.0 0.0
0.5 1.0 0.0
3 0 1 2
"""
    mesh_bytes = ply_content.encode("utf-8")

    # 2. 模拟2张64x64纯色图像(红+蓝)
    images: Dict[str, bytes] = {}
    # 红色图像
    red_img = Image.new("RGB", (64, 64), color="red")
    red_byteio = io.BytesIO()
    red_img.save(red_byteio, format="PNG")
    images["test1.png"] = red_byteio.getvalue()
    # 蓝色图像
    blue_img = Image.new("RGB", (64, 64), color="blue")
    blue_byteio = io.BytesIO()
    blue_img.save(blue_byteio, format="PNG")
    images["test2.png"] = blue_byteio.getvalue()

    # 3. 模拟相机内参(针孔相机,适配64x64图像)
    intrinsics = "0 32.0 32.0 32.0 32.0 0.0 0.0 0.0 0.0"

    # 4. 模拟相机姿态(单位矩阵,相机在z轴2m处)
    pose_matrix = """1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 2.0
0.0 0.0 0.0 1.0"""
    poses = {"test1.png": pose_matrix, "test2.png": pose_matrix}

    return mesh_bytes, images, intrinsics, poses


def run_texturing_with_test_data(texrecon_instance: pytexrecon.TexRecon) -> Tuple[bytes, bytes, Image.Image]:
    """用模拟数据调用TexRecon纹理重建"""
    print("=== 步骤3/3:执行纹理重建 ===")
    mesh_data, images, intrinsics, poses = generate_test_data()
    try:
        textured_mesh_bytes, texture_bytes = texrecon_instance.run_texturing(
            mesh_data=mesh_data,
            images=images,
            intrinsics=intrinsics,
            poses=poses,
            texture_resolution=256,
            fill_holes=True
        )
        texture_img = Image.open(io.BytesIO(texture_bytes))
        return textured_mesh_bytes, texture_bytes, texture_img
    except Exception as e:
        raise RuntimeError(f"纹理重建执行失败:\n{str(e)}")


# -------------------------- 测试流程:分步执行,优先验证实例 --------------------------
def full_test_flow() -> Tuple[str, Optional[pytexrecon.TexRecon], Optional[bytes], Optional[bytes], Optional[Image.Image]]:
    """完整测试流程(分步反馈)"""
    status = ""
    texrecon_instance = None
    textured_mesh_bytes = None
    texture_bytes = None
    texture_img = None

    try:
        # 步骤1:优先初始化TexRecon(核心验证)
        texrecon_instance = init_texrecon()
        status += "✅ 步骤1/3:TexRecon实例初始化成功!\n"
        status += f"- 可执行文件路径:{texrecon_instance.texrecon_path}\n"

        # 步骤2+3:生成数据并执行纹理重建
        textured_mesh_bytes, texture_bytes, texture_img = run_texturing_with_test_data(texrecon_instance)
        status += "✅ 步骤2/3:模拟测试数据生成成功!\n"
        status += "✅ 步骤3/3:纹理重建执行成功!\n"
        status += "- 已生成带纹理模型(.obj)和纹理图(.png)\n"

    except Exception as e:
        status = f"❌ 测试失败:\n{str(e)}"

    return status, texrecon_instance, textured_mesh_bytes, texture_bytes, texture_img


# -------------------------- Gradio界面:修复File.update()错误 --------------------------
with gr.Blocks(title="pytexrecon 分步测试工具") as demo:
    gr.Markdown("# pytexrecon 全流程测试(优先验证TexRecon)")
    gr.Markdown("🔍 已修复Gradio兼容性问题,支持最新版本")

    # 存储TexRecon实例
    texrecon_state = gr.State(None)

    with gr.Row():
        test_btn = gr.Button("🚀 开始全流程测试", variant="primary", size="lg")

    # 结果展示区域
    with gr.Group():
        gr.Markdown("### 测试状态日志")
        status_box = gr.Textbox(label="状态", lines=8, interactive=False, placeholder="点击测试按钮开始...")

        gr.Markdown("### TexRecon可执行文件路径")
        texrecon_path_box = gr.Textbox(label="路径", interactive=False, placeholder="初始化成功后显示...")

        gr.Markdown("### 输出结果")
        with gr.Row():
            texture_preview = gr.Image(label="纹理图预览", interactive=False)
            mesh_download = gr.File(label="带纹理模型(.obj)")
            texture_download = gr.File(label="纹理图(.png)")

    # 绑定按钮事件:使用新的更新方式(移除.update())
    def on_test_click():
        status, texrecon_inst, mesh_bytes, tex_bytes, tex_img = full_test_flow()
        
        # 1. 处理TexRecon路径显示
        texrecon_path = texrecon_inst.texrecon_path if texrecon_inst else "未初始化"
        
        # 2. 处理文件下载组件(直接返回值,不使用.update())
        # 对于文件组件,直接返回 (数据, 文件名) 元组或None
        mesh_file = (mesh_bytes, "test_textured_mesh.obj") if mesh_bytes else None
        texture_file = (tex_bytes, "test_texture.png") if tex_bytes else None

        return (
            status,
            texrecon_inst,
            texrecon_path,
            mesh_file,
            texture_file,
            tex_img
        )

    # 绑定输出映射
    test_btn.click(
        fn=on_test_click,
        outputs=[
            status_box,
            texrecon_state,
            texrecon_path_box,
            mesh_download,
            texture_download,
            texture_preview
        ]
    )


# 启动应用
if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=7860)