当前位置: 首页 > news >正文

基于 OpenCV + OpenGL 的三维重建代码实现

OpenCV 做三维重建(SFM / 点云),再用 OpenGL 实时显示三维结果
示例采用 C++ + OpenCV + OpenGL(GLFW + GLAD),是最常见、最稳定的组合。


一、整体架构

图像输入↓
OpenCV:特征提取 → 相机位姿估计 → 三角化 → 三维点云↓
OpenGL:点云渲染(旋转 / 缩放 / 交互)

二、环境依赖

软件依赖

用途
OpenCV ≥ 4.x 图像处理、特征匹配、三维重建
GLFW OpenGL 窗口管理
GLAD OpenGL 函数加载
GLM 数学矩阵运算
C++17 编译标准

Ubuntu 安装

sudo apt install libopencv-dev libglfw3-dev libglm-dev

三、核心原理(简述)

OpenCV 负责

  • SIFT / ORB 特征提取
  • 两视图几何
  • 本质矩阵 E
  • 三角化得到 3D 点

OpenGL 负责

  • 将点云 (X,Y,Z) 渲染为三维模型
  • 支持鼠标旋转、缩放

四、代码


1、OpenCV 三维重建(SFM 简化版)

reconstruction.cpp

#include <opencv2/opencv.hpp>
#include <opencv2/sfm.hpp>
#include <iostream>
#include <vector>using namespace cv;
using namespace std;int main() {// 1. 读取两张图片Mat img1 = imread("image1.jpg");Mat img2 = imread("image2.jpg");if (img1.empty() || img2.empty()) {cerr << "Image load failed!" << endl;return -1;}// 2. 特征提取(SIFT)Ptr<SIFT> sift = SIFT::create();vector<KeyPoint> kp1, kp2;Mat desc1, desc2;sift->detectAndCompute(img1, noArray(), kp1, desc1);sift->detectAndCompute(img2, noArray(), kp2, desc2);// 3. 特征匹配BFMatcher matcher(NORM_L2);vector<DMatch> matches;matcher.match(desc1, desc2, matches);cout << "Matches: " << matches.size() << endl;// 4. 选择好的匹配点vector<Point2f> pts1, pts2;for (auto& m : matches) {pts1.push_back(kp1[m.queryIdx].pt);pts2.push_back(kp2[m.trainIdx].pt);}// 5. 相机内参(示例)Mat K = (Mat_<double>(3,3) <<800, 0, img1.cols/2,0, 800, img1.rows/2,0, 0, 1);// 6. 本质矩阵Mat E = findEssentialMat(pts1, pts2, K, RANSAC, 0.999, 1.0);// 7. 恢复相机位姿Mat R, t;recoverPose(E, pts1, pts2, K, R, t);// 8. 三角化Mat proj1 = K * Mat::eye(3,4,CV_64F);Mat proj2 = K * (Mat_<double>(3,4) <<R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), t.at<double>(0,0),R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), t.at<double>(1,0),R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), t.at<double>(2,0));Mat pts4D;triangulatePoints(proj1, proj2, pts1, pts2, pts4D);// 9. 转换为三维点云vector<Point3f> points3d;for (int i = 0; i < pts4D.cols; ++i) {Mat pt3d = pts4D.col(i);pt3d /= pt3d.at<float>(3);points3d.emplace_back(pt3d.at<float>(0), pt3d.at<float>(1), pt3d.at<float>(2));}cout << "3D points: " << points3d.size() << endl;// 保存点云FileStorage fs("pointcloud.yml", FileStorage::WRITE);fs << "points" << points3d;fs.release();return 0;
}

输出pointcloud.yml(三维点云)


2、OpenGL 点云显示

viewer.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>using namespace std;// 窗口参数
const int WIDTH = 800, HEIGHT = 600;// 点云数据
vector<glm::vec3> points;// 相机控制
float yaw = -90.0f, pitch = 0.0f;
float camX = 0.0f, camY = 0.0f, camZ = -5.0f;// 加载点云
void loadPointCloud(const string& file) {cv::FileStorage fs(file, cv::FileStorage::READ);cv::FileNode node = fs["points"];cv::FileNodeIterator it = node.begin(), it_end = node.end();for (; it != it_end; ++it) {cv::Point3f p;(*it) >> p;points.emplace_back(p.x, p.y, p.z);}fs.release();
}// 渲染点云
void renderPointCloud(unsigned int VAO, unsigned int shaderProgram) {glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_POINTS, 0, points.size());glBindVertexArray(0);
}int main() {loadPointCloud("pointcloud.yml");glfwInit();GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "3D Reconstruction", nullptr, nullptr);glfwMakeContextCurrent(window);gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);glEnable(GL_DEPTH_TEST);glPointSize(2.0f);// 顶点着色器const char* vertexShaderSource ="#version 330 core\n""layout (location = 0) in vec3 aPos;\n""uniform mat4 view;\n""uniform mat4 projection;\n""void main() {\n""  gl_Position = projection * view * vec4(aPos, 1.0);\n""}";// 片段着色器const char* fragmentShaderSource ="#version 330 core\n""out vec4 FragColor;\n""void main() {\n""  FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n""}";// 编译着色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);glCompileShader(vertexShader);unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);glCompileShader(fragmentShader);unsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// 顶点缓冲unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(glm::vec3), points.data(), GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void*)0);glEnableVertexAttribArray(0);// 视图矩阵glm::mat4 view = glm::lookAt(glm::vec3(camX, camY, camZ),glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3(0.0f, 1.0f, 0.0f));// 投影矩阵glm::mat4 projection = glm::perspective(glm::radians(45.0f),(float)WIDTH / (float)HEIGHT,0.1f,100.0f);// 渲染循环while (!glfwWindowShouldClose(window)) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(shaderProgram);glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, &view[0][0]);glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &projection[0][0]);renderPointCloud(VAO, shaderProgram);glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glfwTerminate();return 0;
}

参考代码 基于opencv和opengl的三维重建的代码 www.youwenfan.com/contentcnu/60277.html

五、编译脚本

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(3DReconstruction)find_package(OpenCV REQUIRED)
find_package(glfw3 REQUIRED)
find_package(glad REQUIRED)
find_package(glm REQUIRED)add_executable(reconstruction reconstruction.cpp)
target_link_libraries(reconstruction ${OpenCV_LIBS})add_executable(viewer viewer.cpp)
target_link_libraries(viewer ${OpenCV_LIBS} glfw glad glm)

六、运行流程

# 1. 三维重建
./reconstruction# 2. 点云显示
./viewer

七、进阶扩展(工业级)

稠密重建

  • COLMAP
  • OpenMVS
  • OpenCV SFM + PMVS

纹理映射

  • UV 展开
  • 贴图投影

实时 SLAM

  • ORB-SLAM3 + OpenGL
  • RTAB-Map

CUDA 加速

  • OpenCV CUDA
  • OpenGL Compute Shader
http://www.jsqmd.com/news/782621/

相关文章:

  • Video DownloadHelper CoApp终极指南:轻松下载网络视频的完整教程
  • 企业级即时通讯「删除消息」:六个场景叠加之后,复杂性超出你的想象
  • # 026 Agent 的文件处理:PDF、Excel、图片、音频的解析与生成
  • 2026年唐山烟道清洗、外墙保洁与商业保洁一站式解决方案深度指南 - 企业名录优选推荐
  • 免费文本挖掘神器KH Coder:三步掌握多语言内容分析技巧
  • 项目改造为 Docker 容器使用指南
  • 不想打工开茶店,预算30万小成本中端预算创业,加盟岩茶品牌哪个不踩坑新手小白全程带教白皮书——以溪谷留香为基准样本的深度决策指南 - 商业科技观察
  • 模型广场功能如何帮助开发者根据任务特性选择合适模型
  • Seraphine:英雄联盟终极智能辅助工具完整指南 - 提升排位胜率的秘密武器
  • PUBG罗技鼠标宏压枪脚本架构揭秘:精准射击的自动化实现方案
  • Java并发编程:从基础到实战的技术探索
  • 性价比高的芯片老化座哪家公司好?
  • Atom编辑器终极中文汉化指南:告别英文困扰,轻松打造专属编程环境
  • 5分钟搭建专业级拼多多数据采集系统:电商运营的终极利器
  • 证书链技术与ADAC安全调试协议详解
  • 2026年唐山烟道清洗与外墙保洁一体化解决方案深度横评 - 企业名录优选推荐
  • FPGA开发实战:Verilog模块库pConst/basic_verilog深度解析与应用指南
  • 深度学习水印去除:无训练图像修复的终极实战方案
  • 如何用FastbootEnhance轻松管理Android设备:Windows终极图形化工具箱指南
  • CANN/ge:昇腾图引擎GE
  • pi0机器人VLA大模型昇腾推理优化
  • 有没有想有偿帮写贪吃蛇编程大作业的(C语言)
  • CANN/hccl AllGatherV接口文档
  • Python 智能体实战:从 0 搭建模块化 Agent 路由系统,落地小龙虾门店运营助手
  • pywencai实战指南:3大场景解决金融数据抓取难题
  • 2026年深圳民办初中择校观察:规范办学提质效,华朗学校成优质选择 - 深度智识库
  • 2026年唐山外墙清洗、烟道保洁与商业保洁服务商深度评测指南 - 企业名录优选推荐
  • 还在被本科终稿 PUA?Paperxie 这波操作直接让你从秃头党变过审王
  • 关于rhel8中的authselect、nss、ipa、pam、sssd、ldap等组件的理解
  • CANN具身智能优化样例