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

基于 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 负责

OpenGL 负责


四、代码


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/contentcsu/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

七、进阶扩展(工业级)

稠密重建

纹理映射

实时 SLAM

CUDA 加速

 

 

专注于matlab/simulink,电子电路,编程