ppsurf / app.py
perler's picture
torch was without cuda compiled
8e4230f
raw
history blame
8.64 kB
#!/usr/bin/env python
from __future__ import annotations
import sys
import os
import datetime
import subprocess
import gradio as gr
import spaces
@spaces.GPU(duration=60 * 3)
def run_on_gpu(input_point_cloud: gr.utils.NamedString,
gen_resolution_global: int,
padding_factor: float,
gen_subsample_manifold_iter: int,
gen_refine_iter: int) -> str:
print('Started inference at {}'.format(datetime.datetime.now()))
print('Inputs:', input_point_cloud, gen_resolution_global, padding_factor,
gen_subsample_manifold_iter, gen_refine_iter)
print('Types:', type(input_point_cloud), type(gen_resolution_global), type(padding_factor),
type(gen_subsample_manifold_iter), type(gen_refine_iter))
sys.path.append(os.path.abspath('ppsurf'))
import uuid
in_file = '{}'.format(input_point_cloud.name)
rand_hash = uuid.uuid4().hex
out_dir = '/tmp/outputs/{}'.format(rand_hash)
out_file_basename = os.path.basename(in_file) + '.ply'
out_file = os.path.join(out_dir, os.path.basename(in_file), out_file_basename)
out_file_gradio = os.path.splitext(in_file)[0] + '_ppsurf.obj'
print('in_file:', in_file)
print('out_dir:', out_dir)
print('out_file:', out_file)
print('out_file_gradio:', out_file_gradio)
os.makedirs(out_dir, exist_ok=True)
model_path = 'models/ppsurf_50nn/version_0/checkpoints/last.ckpt'
args = [
'pps.py', 'predict',
'-c', 'ppsurf/configs/poco.yaml',
'-c', 'ppsurf/configs/ppsurf.yaml',
'-c', 'ppsurf/configs/ppsurf_50nn.yaml',
'--ckpt_path', model_path,
'--data.init_args.in_file', in_file,
'--model.init_args.results_dir', out_dir,
'--trainer.logger', 'False',
'--trainer.devices', '1',
'--model.init_args.gen_resolution_global', str(gen_resolution_global),
'--data.init_args.padding_factor', str(padding_factor),
'--model.init_args.gen_subsample_manifold_iter', str(gen_subsample_manifold_iter),
'--model.init_args.gen_refine_iter', str(gen_refine_iter),
]
sys.argv = args
try:
subprocess.run(['python', 'ppsurf/pps.py'] + args[1:]) # need subprocess to spawn workers
except Exception as e:
gr.Warning("Reconstruction failed:\n{}".format(e))
print('Finished inference at {}'.format(datetime.datetime.now()))
# import shutil
# shutil.copyfile(src=out_file, dst=out_file_gradio)
def _convert_mesh(in_file: str, out_file: str):
import trimesh
mesh = trimesh.load(in_file)
mesh.export(out_file)
_convert_mesh(in_file=out_file, out_file=out_file_gradio)
return out_file_gradio
def main():
print('Main...')
print('Cloning PPSurf...')
# Zero-GPU doesn't work with docker anymore, so here some manual setup
# git submodule doesn't work in Gradio, so we clone it here
subprocess.run(['git', 'clone', 'https://github.com/cg-tuwien/ppsurf.git'])
# subprocess.run(['pip', 'install', '-r', 'ppsurf/requirements', '--no-cache-dir'])
# subprocess.run(['pip', 'install', '-r', 'requirements', '--no-cache-dir'])
print('Cloning PPSurf... Done')
description_header = '# PPSurf: Combining Patches and Point Convolutions for Detailed Surface Reconstruction'
description_col0 = '''## [Github](https://github.com/cg-tuwien/ppsurf)
Supported input file formats:
- PLY, STL, OBJ and other mesh files,
- XYZ as whitespace-separated text file,
- NPY and NPZ (key='arr_0'),
- LAS and LAZ (version 1.0-1.4), COPC and CRS.
Best results for 50k-250k points.
'''
description_col1 = '''## [Project Info](https://www.cg.tuwien.ac.at/research/publications/2024/erler_2024_ppsurf/)
This method is meant for scans of single and few objects.
Quality for scenes and landscapes will be lower.
Reconstructions with default settings will be done in about 30 seconds.
Inference will be terminated after 180 seconds.
'''
# can't render many input types directly in Gradio Model3D
# so we need to convert to supported format
# Gradio can't draw point clouds anyway (2024-03-04), so we skip this for now
# def convert_to_ply(input_point_cloud_upload: gr.utils.NamedString):
#
# # add absolute path to import dirs
# import sys
# import os
# sys.path.append(os.path.abspath('ppsurf'))
#
# # import os
# # os.chdir('ppsurf')
#
# print('Inputs:', input_point_cloud_upload, type(input_point_cloud_upload))
# input_shape: str = input_point_cloud_upload.name
# if not input_shape.endswith('.ply'):
# # load file
# from ppsurf.source.occupancy_data_module import OccupancyDataModule
# pts_np = OccupancyDataModule.load_pts(input_shape)
#
# # convert to ply
# import trimesh
# mesh = trimesh.Trimesh(vertices=pts_np[:, :3])
# input_shape = input_shape + '.ply'
# mesh.export(input_shape)
#
# print('ls:\n', subprocess.run(['ls', os.path.dirname(input_shape)]))
#
# # show in viewer
# print(type(input_tabs))
# # print(type(input_point_cloud_viewer))
# # input_tabs.selected = 'pc_viewer'
# # input_point_cloud_viewer.value = input_shape
with gr.Blocks(css='style.css') as demo:
# descriptions
gr.Markdown(description_header)
with gr.Row():
with gr.Column():
gr.Markdown(description_col0)
with gr.Column():
gr.Markdown(description_col1)
# inputs and outputs
with gr.Row():
with gr.Column():
input_point_cloud_upload = gr.File(show_label=False, file_count='single')
# with gr.Tabs() as input_tabs: # re-enable when Gradio supports point clouds
# with gr.TabItem(label='Input Point Cloud Upload', id='pc_upload'):
# input_point_cloud_upload.upload(
# fn=convert_to_ply,
# inputs=[
# input_point_cloud_upload,
# ],
# outputs=[
# # input_point_cloud_viewer, # not available here
# ])
# with gr.TabItem(label='Input Point Cloud Viewer', id='pc_viewer'):
# input_point_cloud_viewer = gr.Model3D(show_label=False)
gen_resolution_global = gr.Slider(
label='Grid Resolution (larger for more details)',
minimum=17, maximum=513, value=129, step=2)
padding_factor = gr.Slider(
label='Padding Factor (larger if object is cut off at boundaries)',
minimum=0, maximum=1.0, value=0.05, step=0.05)
gen_subsample_manifold_iter = gr.Slider(
label='Subsample Manifold Iterations (larger for larger point clouds)',
minimum=3, maximum=30, value=10, step=1)
gen_refine_iter = gr.Slider(
label='Edge Refinement Iterations (larger for more details)',
minimum=3, maximum=30, value=10, step=1)
with gr.Column():
result_3d_model = gr.Model3D(label='Reconstructed 3D model')
# progress_text = gr.Text(label='Progress')
# with gr.Tabs():
# with gr.TabItem(label='Reconstructed 3D model'):
# result_3d_model = gr.Model3D(show_label=False)
# with gr.TabItem(label='Output mesh file'):
# output_file = gr.File(show_label=False)
with gr.Row():
run_button = gr.Button('Reconstruct with PPSurf')
run_button.click(fn=run_on_gpu,
inputs=[
input_point_cloud_upload,
gen_resolution_global,
padding_factor,
gen_subsample_manifold_iter,
gen_refine_iter,
],
outputs=[
result_3d_model,
# output_file,
# progress_text,
])
demo.queue(max_size=5)
demo.launch(debug=True)
if __name__ == '__main__':
print(os.environ)
main()