基于 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/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
七、进阶扩展(工业级)
稠密重建
- COLMAP
- OpenMVS
- OpenCV SFM + PMVS
纹理映射
- UV 展开
- 贴图投影
实时 SLAM
- ORB-SLAM3 + OpenGL
- RTAB-Map
CUDA 加速
- OpenCV CUDA
- OpenGL Compute Shader