Spaces:
Running
Running
File size: 9,759 Bytes
757ed1c 9650ca8 757ed1c 6264a43 9650ca8 0d45a3b 9650ca8 0d45a3b 9650ca8 0d45a3b 9650ca8 5cfa18d 9650ca8 5cfa18d 9650ca8 5cfa18d 9650ca8 5cfa18d 9650ca8 757ed1c |
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 178 179 180 181 182 183 184 185 186 187 188 189 190 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 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 |
import streamlit as st
import os
import shutil
import zipfile
from space_carving import run_space_carving
from sfm import run_sfm
import open3d as o3d
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go
from helpers import *
st.set_page_config(page_title="3D Reconstruction Web App", layout="wide")
st.markdown("<div style='text-align: center;'><h1>3D Scene Reconstruction</h1></div>", unsafe_allow_html=True)
st.markdown("<div style='text-align: center;'><h2>Computer Vision Course Project</h2></div>", unsafe_allow_html=True)
st.markdown("<div style='text-align: right; font-weight:none;color : gray;'><h5>Course Instructor - Dr. Pratik Mazumdar</h5></div>", unsafe_allow_html=True)
st.markdown(
"<h4><a href='https://github.com/majisouvik26/3d-scene-reconstruction' target='_blank'>Github Link of Project</a></h4>",
unsafe_allow_html=True
)
st.header("Team Member:")
st.markdown("<div> <ul><li>Aditya Sahani(B22CS003)</li><li>Veeraraju Elluru(B22CS080)</li><li>Souvik Maji(B22CS089)</li><li>Dishit Sharma(B22CS082)</li><li>Aditya Rathor(B22AI044)</li></ul></div>", unsafe_allow_html=True)
st.header("Introduction")
st.write("3D scene reconstruction is a fundamental problem in computer vision that involves recovering the three-dimensional structure of a scene from a set of two-dimensional images. " \
"The goal is to generate an accurate and detailed representation of the real world, typically in the form of point clouds, meshes, or volumetric models. This process plays a crucial role in various applications such as robotics, augmented and virtual reality (AR/VR), autonomous navigation, and cultural heritage preservation." \
" The reconstruction pipeline often incorporates techniques like multi-view stereo, Structure from Motion (SfM), and volumetric methods like voxel carving. By leveraging image geometry, camera calibration data, and feature correspondences across views, 3D reconstruction enables machines to perceive and interpret the spatial layout of the physical world.")
st.image("https://filelist.tudelft.nl/BK/Onderzoek/Research_stories/zhaiyu.png", caption="3D Reconstruction")
st.header("Methods Used and Results")
st.subheader("1. NeRF - Neural Radiance Fields (NeRF)")
col1, col2 = st.columns(2)
with col1:
st.image("media/test_image_0.png", width=400, caption="Input Image")
with col2:
st.image("media/truck_reconstruction.gif", width=400, caption="3D Reconstruction")
st.subheader("2. Space Carving")
col1, col2 = st.columns(2)
with col1:
st.image("media/input_images.png", width=400, caption="Input Image")
with col2:
st.image("media/shape_mesh.png", width=400, caption="3D Reconstruction")
st.subheader("3. Pix2Vox")
col1, col2 = st.columns(2)
with col1:
st.image("media/pix.jpg", width=400, caption="Input Image")
with col2:
st.image("media/pix_output.jpg", width=400, caption="3D Reconstruction")
st.subheader("4. SFM Method")
col1, col2 = st.columns(2)
with col1:
st.image("media/DSC_0351.JPG", width=400, caption="Input Image")
with col2:
st.image("media/image.png", width=400, caption="3D Reconstruction")
st.subheader("5. Incremental SFM Method")
col1, col2 = st.columns(2)
with col1:
st.image("media/WhatsApp Image 2025-04-12 at 17.40.27_1137ddf7.jpg", width=400, caption="Input Image")
with col2:
st.image("media/rotation_sfm_cam_1_2_3_4[1].gif", width=400, caption="3D Reconstruction")
st.subheader("6. Gaussian Splatting Method")
col1, col2 = st.columns(2)
with col1:
st.image("media/gs.gif", width=400, caption="Input Image")
with col2:
st.image("media/output_souvik.png", width=400, caption="3D Reconstruction")
st.header("DEMO OF MODELS")
def show_ply_interactive(ply_path):
# Load point cloud
pcd = o3d.io.read_point_cloud(ply_path)
points = np.asarray(pcd.points)
# Optional: use colors
if pcd.has_colors():
colors = np.asarray(pcd.colors)
else:
colors = np.full_like(points, fill_value=0.5) # default gray
# Create interactive plot
fig = go.Figure(data=[go.Scatter3d(
x=points[:, 0], y=points[:, 1], z=points[:, 2],
mode='markers',
marker=dict(
size=1.5,
color=colors,
opacity=0.8
)
)])
fig.update_layout(
scene=dict(
xaxis_title='X', yaxis_title='Y', zaxis_title='Z'
),
width=800,
height=600,
margin=dict(r=10, l=10, b=10, t=10)
)
return fig
# Show PLY as image
# def show_ply_as_image(ply_path):
# # Load point cloud
# pcd = o3d.io.read_point_cloud(ply_path)
# if pcd.is_empty():
# raise ValueError("The .ply file is empty or could not be loaded.")
# # Create visualization window (offscreen)
# vis = o3d.visualization.Visualizer()
# vis.create_window(visible=False)
# vis.add_geometry(pcd)
# # Set camera view
# ctr = vis.get_view_control()
# if ctr is None:
# raise RuntimeError("Failed to get view control from the visualizer.")
# ctr.set_zoom(0.7)
# vis.poll_events()
# vis.update_renderer()
# # Screenshot to numpy
# image = vis.capture_screen_float_buffer(do_render=True)
# vis.destroy_window()
# # Convert to displayable image
# img = (np.asarray(image) * 255).astype(np.uint8)
# return Image.fromarray(img)
# ---------- Function to extract zip ----------
def extract_zip(zip_file, extract_to):
if os.path.exists(extract_to):
shutil.rmtree(extract_to)
os.makedirs(extract_to)
with zipfile.ZipFile(zip_file, 'r') as zip_ref:
zip_ref.extractall(extract_to)
return extract_to
# ---------- SPACE CARVING ----------
st.header("π¦ Space Carving")
st.markdown("""
**Space Carving** is a volumetric method that uses silhouettes from multiple views to reconstruct a 3D object by carving away inconsistent voxels.
π Upload a `.zip` file containing images (JPG/PNG) from different calibrated views.
""")
sc_zip = st.file_uploader("Upload ZIP file for Space Carving", type=["zip"])
if sc_zip:
sc_extract_path = "uploads_spacecarving"
with open("temp_spacecarving.zip", "wb") as f:
f.write(sc_zip.getbuffer())
extract_zip("temp_spacecarving.zip", sc_extract_path)
st.success("Extracted images.")
if st.button("Run Space Carving Model"):
output = run_space_carving() # This should generate the .vtr file
st.success("Model ran successfully.")
# Path to generated .vtr file
vtr_path = "res_space/shape.vtr" # Update if filename differs
if os.path.exists(vtr_path):
st.markdown("### π₯ Download Space Carved VTR File")
with open(vtr_path, "rb") as f:
st.download_button(
label="Download .vtr file",
data=f,
file_name=os.path.basename(vtr_path),
mime="application/octet-stream"
)
else:
st.warning("No .vtr file found. Make sure the model ran successfully.")
# ---------- STRUCTURE FROM MOTION ----------
st.markdown("---")
st.header("π· Structure from Motion (SfM)")
st.markdown("""
**Structure from Motion (SfM)** reconstructs 3D geometry and camera poses from a series of images.
π Upload a `.zip` file containing your image dataset (JPG/PNG).
""")
sfm_zip_file = st.file_uploader("Upload ZIP file for SfM", type=["zip"])
if sfm_zip_file is not None:
zip_name = os.path.splitext(sfm_zip_file.name)[0] # π 'dataset.zip' β 'dataset'
sfm_extract_path = "uploads_sfm"
extract_zip(sfm_zip_file, sfm_extract_path)
st.success(f"Extracted {zip_name} dataset.")
if st.button("Run SfM Model"):
output = run_sfm(os.path.join(sfm_extract_path,zip_name))
st.success("Model ran successfully.")
# Construct PLY path based on zip filename
ply_path = os.path.join("res", f"{zip_name}.ply")
if os.path.exists(ply_path):
st.markdown("### π§© Reconstructed Point Cloud Image")
# image = show_ply_as_image(ply_path)
# st.image(image, caption=f"{zip_name}.ply", use_column_width=True)
# Optional download
with open(ply_path, "rb") as f:
st.download_button(
label="π₯ Download .ply file",
data=f,
file_name=f"{zip_name}.ply",
mime="application/octet-stream"
)
else:
st.warning(f"No .ply file named {zip_name}.ply found in 'res/'.")
if os.path.exists(ply_path):
st.markdown("### π§© Reconstructed Point Cloud (Interactive)")
fig = show_ply_interactive(ply_path)
st.plotly_chart(fig, use_container_width=True)
st.header("π§ Pix2Vox")
uploaded_images = st.file_uploader(f"Upload images", accept_multiple_files=True, type=["png", "jpg", "jpeg"])
# print(uploaded_images)
# --- DISPLAY ---
if uploaded_images:
st.subheader("Uploaded Input Views")
cols = st.columns(len(uploaded_images))
rendering_images = []
for i, uploaded_file in enumerate(uploaded_images):
img = Image.open(uploaded_file)
cols[i].image(img, caption=f"View {i+1}", use_container_width=True)
img_np = np.array(img).astype(np.float32) / 255.0
rendering_images.append(img_np)
if st.button("Submit for Reconstruction"):
gv=None
with st.spinner("Reconstructing..."):
gv = predict_voxel_from_images(rendering_images)
fig = voxel_to_plotly(gv)
st.plotly_chart(fig, use_container_width=True)
else:
st.info(f"Upload images to continue.")
|