# Copyright 2023-2025 Marigold Team, ETH Zürich. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # -------------------------------------------------------------------------- # More information about Marigold: # https://marigoldmonodepth.github.io # https://marigoldcomputervision.github.io # Efficient inference pipelines are now part of diffusers: # https://huggingface.co/docs/diffusers/using-diffusers/marigold_usage # https://huggingface.co/docs/diffusers/api/pipelines/marigold # Examples of trained models and live demos: # https://huggingface.co/prs-eth # Related projects: # https://rollingdepth.github.io/ # https://marigolddepthcompletion.github.io/ # Citation (BibTeX): # https://github.com/prs-eth/Marigold#-citation # If you find Marigold useful, we kindly ask you to cite our papers. # -------------------------------------------------------------------------- import os import tempfile import gradio as gr from PIL import Image from extrude import extrude_depth_3d from gradio_patches.examples import Examples default_seed = 2024 default_batch_size = 4 default_bas_plane_near = 0.0 default_bas_plane_far = 1.0 default_bas_embossing = 20 default_bas_size_longest_px = 512 default_bas_size_longest_cm = 10 default_bas_filter_size = 3 default_bas_frame_thickness = 5 default_bas_frame_near = 1 default_bas_frame_far = 1 def process_bas( path_input_depth, path_input_rgb=None, plane_near=default_bas_plane_near, plane_far=default_bas_plane_far, embossing=default_bas_embossing, size_longest_px=default_bas_size_longest_px, size_longest_cm=default_bas_size_longest_cm, filter_size=default_bas_filter_size, frame_thickness=default_bas_frame_thickness, frame_near=default_bas_frame_near, frame_far=default_bas_frame_far, ): if path_input_depth is None: raise gr.Error( "Missing image in the first pane: upload a file or use one from the gallery below." ) input_depth = Image.open(path_input_depth) if input_depth.mode not in ("I", "I;16"): raise gr.Error( f"Input depth must be a 16-bit PNG image of a depth map, found {input_depth.mode}" ) depth_longest_px = max(input_depth.size) input_rgb = None if path_input_rgb is not None: input_rgb = Image.open(path_input_rgb).convert("RGB") if ( input_depth.size[0] * input_rgb.size[1] != input_depth.size[0] * input_rgb.size[1] ): raise gr.Error( f"Inputs have incompatible dimensions: {input_depth.size} and {input_rgb.size}" ) if plane_near >= plane_far: raise gr.Error("NEAR plane must have a value smaller than the FAR plane") name_base, name_ext = os.path.splitext(os.path.basename(path_input_depth)) print(f"Processing bas-relief {name_base}{name_ext}") path_output_dir = tempfile.mkdtemp() def _process_3d( size_longest_px, filter_size, vertex_colors, scene_lights, output_model_scale=None, prepare_for_3d_printing=False, zip_outputs=False, ): image_new_w = size_longest_px * input_depth.width // depth_longest_px image_new_h = size_longest_px * input_depth.height // depth_longest_px image_new_sz = (image_new_w, image_new_h) path_depth_new = os.path.join( path_output_dir, f"{name_base}_depth_{size_longest_px}.png" ) ( input_depth.convert(mode="F") .resize(image_new_sz, Image.BILINEAR) .convert("I") .save(path_depth_new) ) path_rgb_new = None if input_rgb is not None: path_rgb_new = os.path.join( path_output_dir, f"{name_base}_rgb_{size_longest_px}{name_ext}" ) input_rgb.resize(image_new_sz, Image.LANCZOS).save(path_rgb_new) path_glb, path_stl, path_obj = extrude_depth_3d( path_depth_new, path_rgb_new, output_model_scale=( size_longest_cm * 10 if output_model_scale is None else output_model_scale ), filter_size=filter_size, coef_near=plane_near, coef_far=plane_far, emboss=embossing / 100, f_thic=frame_thickness / 100, f_near=frame_near / 100, f_back=frame_far / 100, vertex_colors=vertex_colors, scene_lights=scene_lights, prepare_for_3d_printing=prepare_for_3d_printing, zip_outputs=zip_outputs, ) return path_glb, path_stl, path_obj path_viewer_glb, _, _ = _process_3d( 256, filter_size, vertex_colors=False, scene_lights=True, output_model_scale=1 ) path_files_glb, path_files_stl, path_files_obj = _process_3d( size_longest_px, filter_size, vertex_colors=True, scene_lights=False, prepare_for_3d_printing=True, zip_outputs=True, ) return path_viewer_glb, [path_files_glb, path_files_stl, path_files_obj] with gr.Blocks( title="Depth To 3D Print", css=""" #download { height: 118px; } .viewport { aspect-ratio: 4/3; } h1 { text-align: center; display: block; } h2 { text-align: center; display: block; } h3 { text-align: center; display: block; } a { display: inline-block; } .md_feedback li { margin-bottom: 0px !important; } ol { margin: 0 auto; width: fit-content; text-align: left; } ol li { margin-bottom: 0px; } """, head=""" """, ) as demo: gr.Markdown( """ # Depth To 3D Print
Start exploring the interactive bas-relief examples at the bottom of the page!
To create your own watertight 3D-printable bas-relief depth map: