【3D算法技术入门】如何基于建筑图片重建三维数字资产?

要基于建筑图片重建三维数字资产是一个复杂的计算机视觉任务,涉及图像采集、特征提取、相机姿态估计、稠密重建和三维模型优化等多个步骤。下面我将提供一个基于Python的解决方案框架,使用开源库实现从图片到三维模型的基本流程。

首先需要安装必要的库:

bash 复制代码
pip install opencv-python numpy matplotlib pycolmap trimesh open3d

下面是实现的核心代码,包含了从图像加载、特征匹配到三维点云生成的完整流程:

python 复制代码
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_dir
        self.output_dir = output_dir
        self.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 = 1024
            if 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_paths
        print(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()

使用说明

这个代码实现了从建筑图片到三维模型的完整流程,主要分为以下几个步骤:

  1. 数据准备

    • 在"building_images"文件夹中放入从小红书收集的建筑图片
    • 建议收集15-30张不同角度、不同光照条件下的图片,覆盖建筑各个面
  2. 代码运行

    • 运行脚本后,程序会自动进行图像预处理
    • 接着进行特征提取和匹配,构建稀疏点云
    • 然后生成稠密点云并构建三维网格模型
    • 最后可视化结果并保存模型文件
  3. 结果输出

    • 处理后的图片
    • 稀疏点云和稠密点云数据
    • 最终的三维网格模型(PLY格式),可导入Blender等软件进一步编辑

注意事项

  1. 图片质量对重建结果影响很大,建议使用清晰、光照均匀的图片
  2. 拍摄时尽量围绕建筑移动,保持重叠区域,避免剧烈视角变化
  3. 对于复杂建筑,可能需要更多图片和后期手动优化
  4. 该代码需要安装COLMAP软件,具体安装方法请参考官方文档
  5. 从网络获取图片时请注意遵守版权规定和平台条款

如果需要更高质量的重建结果,可以考虑使用专业的三维重建软件如Agisoft Metashape,或在这个基础上增加纹理映射、模型简化等步骤。

相关推荐
0wioiw019 小时前
算法(③二叉树)
算法
WHS-_-202219 小时前
Carrier Aggregation Enabled MIMO-OFDM Integrated Sensing and Communication
算法
何妨重温wdys19 小时前
贪心算法解决活动选择问题:最多不重叠活动数量求解
算法·贪心算法
闻缺陷则喜何志丹19 小时前
【有序集合 有序映射 懒删除堆】 3510. 移除最小数对使数组有序 II|2608
c++·算法·力扣·有序集合·有序映射·懒删除堆
cheniie20 小时前
网格纹理采样算法
算法
诗人啊_程序员1 天前
AI、人工智能基础: 模型剪枝的概念与实践(PyTorch版)
人工智能·pytorch·算法·ai·剪枝
好名字更能让你们记住我1 天前
Linux网络基础1(一)之计算机网络背景
linux·服务器·网络·windows·计算机网络·算法·centos
unicrom_深圳市由你创科技1 天前
机器人视觉检测
图像处理·机器人·视觉检测
做科研的周师兄1 天前
【机器学习入门】4.1 聚类简介——从“物以类聚”看懂无监督分组的核心逻辑
javascript·人工智能·算法·机器学习·支持向量机·聚类