Files
2025-06-29 20:15:51 +08:00

285 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""
Web visualization version - Generate interactive HTML using plotly
Point cloud data visualization tool with 3D interactive display support
"""
import os
import sys
import numpy as np
import open3d as o3d
import plotly.graph_objects as go
def get_default_paths():
"""Get default file paths"""
# Get the directory where the script is located (tools directory)
script_dir = os.path.dirname(os.path.abspath(__file__))
# Get project root directory (parent directory of tools)
project_root = os.path.dirname(script_dir)
# Default PCD file paths (search in project root directory)
possible_pcd_paths = [
os.path.join(project_root, "test_data", "map_only23456.pcd"),
os.path.join(project_root, "test_data", "0619", "1", "output.pcd"),
os.path.join(project_root, "utm_test", "3", "output.pcd"),
]
# Find existing PCD files
for pcd_path in possible_pcd_paths:
if os.path.exists(pcd_path):
return pcd_path, os.path.join(project_root, "web_visualization")
# If not found, return the first path as default
return possible_pcd_paths[0], os.path.join(project_root, "web_visualization")
def find_pcd_files(directory):
"""Find all PCD files in the specified directory"""
pcd_files = []
for root, dirs, files in os.walk(directory):
for file in files:
if file.lower().endswith(".pcd"):
pcd_files.append(os.path.join(root, file))
return pcd_files
def create_3d_visualization(pcd, output_dir="web_output", title="Point Cloud"):
"""Create 3D interactive visualization"""
os.makedirs(output_dir, exist_ok=True)
points = np.asarray(pcd.points)
x, y, z = points[:, 0], points[:, 1], points[:, 2]
# Create 3D scatter plot
fig_3d = go.Figure(
data=[
go.Scatter3d(
x=x,
y=y,
z=z,
mode="markers",
marker=dict(
size=2,
color="steelblue", # Use single color
opacity=0.8,
),
text=[
f"X: {x[i]:.3f}<br>Y: {y[i]:.3f}<br>Z: {z[i]:.3f}"
for i in range(min(1000, len(x)))
], # Only add hover info for the first 1000 points
hoverinfo="text",
name="Point Cloud",
)
]
)
fig_3d.update_layout(
title=dict(
text="Interactive 3D Point Cloud Visualization", x=0.5, font=dict(size=20)
),
scene=dict(
xaxis_title="X (m)",
yaxis_title="Y (m)",
zaxis_title="Z (m)",
aspectmode="cube", # Use cube mode to maintain proportions and center
camera=dict(
eye=dict(x=0, y=0, z=2.5), # Set camera position for centered top view
center=dict(x=0, y=0, z=0), # Set view center point
),
),
width=1000,
height=700,
margin=dict(l=50, r=50, t=80, b=50), # Adjust margins to center the graph
)
# Save 3D visualization
html_3d_path = os.path.join(output_dir, "pointcloud_3d.html")
fig_3d.write_html(html_3d_path)
return html_3d_path
def create_simple_index(output_dir, html_3d_path):
"""Create simplified index page"""
html_content = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Point Cloud Visualization</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1000px;
margin: 0 auto;
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
text-align: center;
}
.header {
margin-bottom: 30px;
border-bottom: 2px solid #007bff;
padding-bottom: 20px;
}
.header h1 {
color: #333;
margin: 0;
}
.header p {
color: #666;
margin: 10px 0 0 0;
}
.btn {
display: inline-block;
background-color: #007bff;
color: white;
padding: 15px 30px;
text-decoration: none;
border-radius: 8px;
font-size: 18px;
margin: 20px 0;
transition: background-color 0.2s;
}
.btn:hover {
background-color: #0056b3;
}
.solution-box {
background-color: #e8f5e8;
border: 1px solid #28a745;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
}
.solution-box h3 {
color: #28a745;
margin-top: 0;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎯 3D Point Cloud Interactive Visualization</h1>
</div>
<a href="pointcloud_3d.html" class="btn">🌐 Open 3D Point Cloud Visualization</a>
<div style="margin-top: 40px; padding: 20px; background-color: #f8f9fa; border-radius: 8px; text-align: center;">
<h3>💡 Usage Instructions</h3>
<p>Click the button above to open the 3D visualization page and use mouse for interactive operations:</p>
<ul style="display: inline-block; text-align: left; margin: 0; padding-left: 20px;">
<li>Drag: Rotate view</li>
<li>Scroll wheel: Zoom</li>
<li>Right-click drag: Pan</li>
<li>Hover: View point coordinates</li>
</ul>
</div>
</div>
</body>
</html>
"""
index_path = os.path.join(output_dir, "index.html")
with open(index_path, "w", encoding="utf-8") as f:
f.write(html_content)
return index_path
def main():
"""Main function"""
print("=== Image2PCD Web Visualization Tool ===")
# Get default paths
default_pcd_path, default_output_dir = get_default_paths()
# Check for command line arguments
if len(sys.argv) > 1:
pcd_path = sys.argv[1]
if not os.path.exists(pcd_path):
print(f"Error: Specified PCD file does not exist: {pcd_path}")
return
else:
pcd_path = default_pcd_path
if not os.path.exists(pcd_path):
print(f"Warning: Default PCD file does not exist: {pcd_path}")
# Try to find other PCD files
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir)
print("Searching for PCD files...")
pcd_files = find_pcd_files(project_root)
if pcd_files:
pcd_path = pcd_files[0]
print(f"Found PCD file: {pcd_path}")
else:
print("Error: No PCD files found")
print(
"Please ensure there are PCD files in the project, or specify file path via command line"
)
print("Usage: python pcd_web.py <pcd_file_path>")
return
# Set output directory
if len(sys.argv) > 2:
output_dir = sys.argv[2]
else:
output_dir = default_output_dir
print(f"Input file: {pcd_path}")
print(f"Output directory: {output_dir}")
# Load point cloud
print("Loading point cloud file...")
pcd = o3d.io.read_point_cloud(pcd_path)
if len(pcd.points) == 0:
print("Error: Unable to load point cloud file or file is empty")
print("Please check if the file format is correct")
return
print(f"Successfully loaded point cloud with {len(pcd.points)} points")
# Get filename as title
pcd_filename = os.path.basename(pcd_path)
title = f"Point Cloud: {pcd_filename}"
# Create 3D visualization
print("Generating 3D visualization...")
html_3d_path = create_3d_visualization(pcd, output_dir, title)
# Create index page
print("Generating index page...")
index_path = create_simple_index(output_dir, html_3d_path)
print("\n3D visualization created successfully!")
print(f"Output directory: {os.path.abspath(output_dir)}")
print(f"Main page: {os.path.abspath(index_path)}")
print(f"3D visualization: {os.path.abspath(html_3d_path)}")
print("\nUsage:")
print(f"1. Open in browser: file://{os.path.abspath(index_path)}")
print(f"2. Or open directly: file://{os.path.abspath(html_3d_path)}")
# Try to automatically open browser (optional)
try:
import webbrowser
webbrowser.open(f"file://{os.path.abspath(index_path)}")
print("Attempted to open visualization page in default browser")
except ImportError:
pass
if __name__ == "__main__":
main()