File size: 3,649 Bytes
84ff87e
c045ba0
84ff87e
 
 
 
 
 
c045ba0
84ff87e
 
 
 
c045ba0
84ff87e
 
c045ba0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84ff87e
c045ba0
 
 
 
 
 
 
84ff87e
c045ba0
84ff87e
 
 
c045ba0
 
84ff87e
 
 
 
 
c045ba0
84ff87e
c045ba0
84ff87e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c045ba0
 
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
import streamlit as st
import cv2
import open3d as o3d
import numpy as np
import tempfile
import os

# Title of the App
st.title("3D Reconstruction Tool from Video πŸ“Ή β†’ πŸ› οΈ β†’ 🧊")

# Sidebar: Information
st.sidebar.write("""
## About the App
Upload a video file, extract frames, reconstruct a 3D point cloud using Structure from Motion (SfM), and visualize or download the 3D mesh.
""")

# Step 1: Upload Video File
uploaded_file = st.file_uploader("Upload a Video File (MP4, AVI)", type=["mp4", "avi"])

# Function to extract frames from video
def extract_frames(video_path, frame_rate=10):
    cap = cv2.VideoCapture(video_path)
    frames = []
    count = 0
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        if count % frame_rate == 0:
            frames.append(frame)
        count += 1
    cap.release()
    return frames

# Function to save frames as images
def save_frames_as_images(frames, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    for i, frame in enumerate(frames):
        filename = os.path.join(output_dir, f"frame_{i:04d}.png")
        cv2.imwrite(filename, frame)

# Step 2: Process Uploaded Video
if uploaded_file:
    st.video(uploaded_file)
    st.write("Extracting frames...")

    # Save the uploaded video temporarily
    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
        tmp_video.write(uploaded_file.read())
        video_path = tmp_video.name

    # Extract frames
    frames = extract_frames(video_path, frame_rate=10)
    st.write(f"βœ… Extracted {len(frames)} frames from the video.")

    # Save extracted frames
    frames_dir = tempfile.mkdtemp()
    save_frames_as_images(frames, frames_dir)
    st.write(f"Frames saved temporarily at `{frames_dir}`.")

    # Step 3: Structure from Motion (3D Reconstruction)
    st.write("πŸ”„ Reconstructing 3D point cloud using Structure from Motion...")
    
    # Create Open3D Point Cloud
    pcd = o3d.geometry.PointCloud()
    for image_file in sorted(os.listdir(frames_dir)):
        img_path = os.path.join(frames_dir, image_file)
        frame = cv2.imread(img_path)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        # Dummy point cloud generation for simplicity
        height, width = gray.shape
        x, y = np.meshgrid(np.arange(width), np.arange(height))
        z = gray / 255.0  # Use gray intensity as a pseudo depth
        points = np.stack((x.flatten(), y.flatten(), z.flatten()), axis=1)
        pcd.points.extend(o3d.utility.Vector3dVector(points))

    # Step 4: Surface Reconstruction
    st.write("πŸ› οΈ Generating mesh using Poisson Reconstruction...")
    pcd.estimate_normals()
    mesh, _ = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=8)

    # Step 5: Visualization
    st.write("βœ… Reconstruction Complete! Visualizing the 3D model:")
    o3d.io.write_triangle_mesh("reconstructed_mesh.stl", mesh)

    # Use Plotly for visualization
    import plotly.graph_objects as go
    vertices = np.asarray(mesh.vertices)
    triangles = np.asarray(mesh.triangles)
    fig = go.Figure(data=[go.Mesh3d(
        x=vertices[:, 0],
        y=vertices[:, 1],
        z=vertices[:, 2],
        i=triangles[:, 0],
        j=triangles[:, 1],
        k=triangles[:, 2],
        color='lightblue',
        opacity=0.50
    )])
    st.plotly_chart(fig)

    # Step 6: Download the Optimized Mesh
    st.write("πŸ“₯ Download the reconstructed 3D model:")
    with open("reconstructed_mesh.stl", "rb") as f:
        st.download_button("Download 3D Mesh (STL)", f, file_name="reconstructed_3D_Model.stl")