要基于建筑圖片重建三維數字資產是一個復雜的計算機視覺任務,涉及圖像采集、特征提取、相機姿態估計、稠密重建和三維模型優化等多個步驟。下面我將提供一個基于Python的解決方案框架,使用開源庫實現從圖片到三維模型的基本流程。
首先需要安裝必要的庫:
pip install opencv-python numpy matplotlib pycolmap trimesh open3d
下面是實現的核心代碼,包含了從圖像加載、特征匹配到三維點云生成的完整流程:
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
import trimesh
import open3d as o3d
from pycolmap import Reconstruction, Image, Point3D# 1. 準備工作:設置路徑和參數
class BuildingReconstructor:def __init__(self, image_dir, output_dir):self.image_dir = image_dirself.output_dir = output_dirself.image_paths = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]self.reconstruction = None# 創建輸出目錄os.makedirs(output_dir, exist_ok=True)os.makedirs(os.path.join(output_dir, 'sparse'), exist_ok=True)os.makedirs(os.path.join(output_dir, 'dense'), exist_ok=True)# 2. 圖像預處理def preprocess_images(self):"""對圖像進行預處理,包括 resize 和去畸變"""processed_dir = os.path.join(self.output_dir, 'processed_images')os.makedirs(processed_dir, exist_ok=True)processed_paths = []for img_path in self.image_paths:img = cv2.imread(img_path)# 調整圖像大小,保持比例h, w = img.shape[:2]max_dim = 1024if max(h, w) > max_dim:scale = max_dim / max(h, w)img = cv2.resize(img, (int(w*scale), int(h*scale)))# 保存處理后的圖像filename = os.path.basename(img_path)save_path = os.path.join(processed_dir, filename)cv2.imwrite(save_path, img)processed_paths.append(save_path)self.image_paths = processed_pathsprint(f"預處理完成,共 {len(processed_paths)} 張圖片")return processed_paths# 3. 特征提取與匹配(使用COLMAP進行稀疏重建)def run_sparse_reconstruction(self):"""使用COLMAP進行稀疏重建,獲取相機參數和稀疏點云"""print("開始稀疏重建...")# 調用COLMAP進行特征提取和匹配from pycolmap import feature_extractor, exhaustive_matcher, mapper# 特征提取feature_extractor(database_path=os.path.join(self.output_dir, 'database.db'),image_path=self.image_dir,image_list=self.image_paths,camera_mode=0 # 自動選擇相機模型)# 特征匹配exhaustive_matcher(database_path=os.path.join(self.output_dir, 'database.db'))# 三維重建self.reconstruction = mapper(database_path=os.path.join(self.output_dir, 'database.db'),image_path=self.image_dir,output_path=os.path.join(self.output_dir, 'sparse'),verbose=True)print(f"稀疏重建完成,生成 {len(self.reconstruction.points3D)} 個三維點")return self.reconstruction# 4. 稠密重建(生成密集點云)def run_dense_reconstruction(self):"""基于稀疏重建結果進行稠密重建"""if not self.reconstruction:raise ValueError("請先進行稀疏重建")print("開始稠密重建...")# 這里簡化實現,實際項目中可以使用OpenMVS或COLMAP的稠密重建模塊# 導出稀疏點云points = []colors = []for p3d in self.reconstruction.points3D.values():points.append(p3d.xyz)colors.append(p3d.color / 255.0)# 轉換為Open3D點云pcd = o3d.geometry.PointCloud()pcd.points = o3d.utility.Vector3dVector(np.array(points))pcd.colors = o3d.utility.Vector3dVector(np.array(colors))# 點云下采樣和去噪pcd = pcd.voxel_down_sample(voxel_size=0.05)cl, ind = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0)pcd = pcd.select_by_index(ind)# 保存稠密點云dense_pcd_path = os.path.join(self.output_dir, 'dense', 'point_cloud.ply')o3d.io.write_point_cloud(dense_pcd_path, pcd)print(f"稠密點云保存至 {dense_pcd_path},包含 {len(pcd.points)} 個點")return pcd# 5. 三維模型生成(從點云創建網格)def generate_mesh(self, pcd):"""從點云生成三維網格模型"""print("開始生成三維網格...")# 估計法向量pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))# 使用泊松表面重建生成網格with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9)# 裁剪低密度區域vertices_to_keep = densities > np.quantile(densities, 0.01)mesh = mesh.select_by_index(np.where(vertices_to_keep)[0])# 保存網格模型mesh_path = os.path.join(self.output_dir, 'building_mesh.ply')o3d.io.write_triangle_mesh(mesh_path, mesh)print(f"三維網格模型保存至 {mesh_path}")return mesh# 6. 可視化結果def visualize_results(self, pcd=None, mesh=None):"""可視化點云和網格模型"""if pcd:print("可視化點云...")o3d.visualization.draw_geometries([pcd], window_name="建筑點云")if mesh:print("可視化網格模型...")o3d.visualization.draw_geometries([mesh], window_name="建筑三維模型")# 執行完整流程def run_pipeline(self):"""執行完整的三維重建流程"""self.preprocess_images()self.run_sparse_reconstruction()pcd = self.run_dense_reconstruction()mesh = self.generate_mesh(pcd)self.visualize_results(pcd, mesh)return mesh# 主函數
def main():# 設置圖片目錄和輸出目錄image_dir = "building_images" # 存放從小紅書收集的建筑圖片output_dir = "reconstruction_results"# 確保圖片目錄存在if not os.path.exists(image_dir) or len(os.listdir(image_dir)) == 0:print(f"錯誤:圖片目錄 {image_dir} 不存在或為空")print("請先在該目錄下放置建筑的多角度圖片")return# 創建重建器并運行reconstructor = BuildingReconstructor(image_dir, output_dir)mesh = reconstructor.run_pipeline()print("三維重建流程完成!")if __name__ == "__main__":main()
使用說明
這個代碼實現了從建筑圖片到三維模型的完整流程,主要分為以下幾個步驟:
-
數據準備:
- 在"building_images"文件夾中放入從小紅書收集的建筑圖片
- 建議收集15-30張不同角度、不同光照條件下的圖片,覆蓋建筑各個面
-
代碼運行:
- 運行腳本后,程序會自動進行圖像預處理
- 接著進行特征提取和匹配,構建稀疏點云
- 然后生成稠密點云并構建三維網格模型
- 最后可視化結果并保存模型文件
-
結果輸出:
- 處理后的圖片
- 稀疏點云和稠密點云數據
- 最終的三維網格模型(PLY格式),可導入Blender等軟件進一步編輯
注意事項
- 圖片質量對重建結果影響很大,建議使用清晰、光照均勻的圖片
- 拍攝時盡量圍繞建筑移動,保持重疊區域,避免劇烈視角變化
- 對于復雜建筑,可能需要更多圖片和后期手動優化
- 該代碼需要安裝COLMAP軟件,具體安裝方法請參考官方文檔
- 從網絡獲取圖片時請注意遵守版權規定和平臺條款
如果需要更高質量的重建結果,可以考慮使用專業的三維重建軟件如Agisoft Metashape,或在這個基礎上增加紋理映射、模型簡化等步驟。