opencv视差图三维点云PCl
时间: 2025-05-11 17:21:07 浏览: 29
### 使用 OpenCV 和 PCL 将 2D 图像转换为 3D 点云
为了完成从二维图像生成三维点云的任务,可以按照以下方法操作:
#### 1. 加载图像并计算视差图
使用 OpenCV 提供的 `stereoBM` 或者 `stereoSGBM` 函数来生成视差图。这些函数基于立体视觉原理,利用两幅相机拍摄的左、右图像计算出对应像素之间的位移。
以下是加载图像并生成视差图的代码示例:
```cpp
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/calib3d.hpp>
int main() {
cv::Mat img_left = cv::imread("left_image.png", cv::IMREAD_GRAYSCALE);
cv::Mat img_right = cv::imread("right_image.png", cv::IMREAD_GRAYSCALE);
int numDisparities = 16 * 5; // 设置视差范围
int blockSize = 9; // 块大小
cv::Ptr<cv::StereoBM> sbm = cv:: StereoBM::create(numDisparities, blockSize);
cv::Mat disparity;
sbm->compute(img_left, img_right, disparity);
double minVal, maxVal;
cv::minMaxLoc(disparity, &minVal, &maxVal); // 归一化视差图以便可视化
disparity.convertTo(disparity, CV_8U, 255 / (maxVal - minVal));
cv::imshow("disparity", disparity);
cv::waitKey(0);
}
```
这段代码实现了视差图的生成过程[^1]。
---
#### 2. 转换视差图为深度图
视差图表示的是两个摄像头之间像素位置的变化量,而深度信息可以通过几何关系推导得出。假设已知焦距 \(f\) 和基线距离 \(B\)(即两个摄像头中心的距离),则深度 \(Z\) 可由下式计算:
\[ Z = \frac{f \cdot B}{\text{disparity}} \]
因此,在获取视差图之后,可以根据该公式进一步计算深度值。
---
#### 3. 构建点云数据结构
一旦获得了深度图,就可以逐像素构建点云坐标系下的三维点集合。对于每一个有效像素点 \((u,v)\),其对应的三维空间坐标可按如下方式定义:
\[ X = \frac{(u - c_x) \cdot Z}{f} \]
\[ Y = \frac{(v - c_y) \cdot Z}{f} \]
其中,\(c_x\) 和 \(c_y\) 是主点偏移参数;\(f\) 表示焦距。
下面是将深度图转化为点云的具体实现:
```cpp
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/cloud_viewer.h>
void convertDepthImageToPointcloud(const cv::Mat& depthMap, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
float fx = 525.0f; // 相机内参矩阵中的fx
float fy = 525.0f; // 相机内参矩阵中的fy
float cx = 319.5f; // 主点cx
float cy = 239.5f; // 主点cy
for(int v=0; v<depthMap.rows; ++v){
for(int u=0; u<depthMap.cols; ++u){
unsigned short d = depthMap.ptr<unsigned short>(v)[u];
if(d == 0){ continue;} // 如果深度值为空,则跳过当前点
float z = d / 1000.0f; // 单位转换:毫米 -> 米
float x = (u - cx) * z / fx;
float y = (v - cy) * z / fy;
cloud->points.push_back(pcl::PointXYZ(x,y,z));
}
}
cloud->width = static_cast<uint32_t>(cloud->points.size());
cloud->height = 1;
}
int main(){
cv::Mat depthMap = cv::imread("depth_map.png", cv::IMREAD_ANYDEPTH);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
convertDepthImageToPointcloud(depthMap, cloud);
pcl::io::savePCDFileASCII ("output.pcd", *cloud);
std::cout << "Saved point cloud with " << cloud->size () << " points." << std::endl;
pcl::visualization::CloudViewer viewer("Simple Cloud Viewer");
viewer.showCloud(cloud);
while (!viewer.wasStopped ()) {}
}
```
以上代码展示了如何把深度图映射成点云,并保存为 `.pcd` 文件用于后续分析或显示[^4]。
---
#### 总结
整个流程分为三个主要部分:一是通过双目摄像机制作视差图;二是依据几何模型求解实际物体离镜头远近程度——也就是所谓的“深度”;三是借助所获得的数据建立完整的三维重建成果集。最终产物能够被导入至其他应用程序当中做更深入的研究或者展示用途[^2]。
阅读全文
相关推荐



















