提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
opencv处理深度图,和处理普通图像差不多,但是有一些地方需要注意。
-
opencv数据类型对应关系:
-
opencv数据类型对应的解释:
一、opencv读取深度图
深度图为tiff文件,一般是单通道32位,也即CV_32F(对应5,也即float类型)。有必要在读取图像后,输出一下数据类型,以防后续对像素进行操作时出现错误
cv::Mat img = cv::imread("../.tiff", -1);
std::cout << "img.type() = " << img.type() << std::endl;
if (img.empty()) {
cout << "请检查文件名称是否有误!" << endl;
return -1;
}
深度图为png文件,一般是单通道16位,也即CV_16U(对应2,也即ushort)。
二、opencv处理深度图像素
以float类型为例:
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
cout << "d= " << img.at<float>(i, j) << endl;
cout << "d = " << img.ptr<float>(i)[j] << endl;
}
}
考虑到png格式的深度图,根据type类型,将float改成short或者ushort即可
三、opencv处理深度图
1.中值滤波
cv::Mat median;
cv::medianBlur(depth, median, 5);//对于深度图,卷积核大小只能为3或5
2.高斯滤波
cv::Mat gauss;
cv::GaussianBlur(depth, gauss, cv::Size(3, 3), 5, 5);
3.求梯度
cv::Mat xgrad, ygrad;
//这里为什么用CV_32F, 因为深度图是CV_16U,我们设置输出图像的深度比灰度图更大, 就可以容纳更大的特征值, 提取效果也就更明显,
//你也可以填-1等同于输入图像的深度,但是反正不能小于输入图像的深度。
//cv::Scharr(median, xgrad, CV_32F, 1, 0);
//cv::Scharr(median, ygrad, CV_32F, 0, 1);
cv::Sobel(depth, xgrad, CV_32F, 1, 0, 3); // 使用Gx
cv::Sobel(depth, ygrad, CV_32F, 0, 1, 3); // 使用Gy
//这个函数的作用是保证Sobel算子操作过后有些负数结果值不被置为0, 也就是不被截取掉
cv::convertScaleAbs(xgrad, xgrad);
cv::convertScaleAbs(ygrad, ygrad);
cv::Mat xygrad = cv::Mat(xgrad.size(), xgrad.type()); // 初始化图像
cv::addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
四、深度图转点云
这里是单通道的深度图,也即非彩色;对于彩色图,遍历时需要m+=3,彩色信息按照已注释部分添加即可
float fx = ...;
float fy = ...;
float cx = ...;
float cy = ...;
for (int m = 0; m < depth.rows; m++)//循环遍历新的关键帧的深度值的行
{
for (int n = 0; n < depth.cols; n++)//循环遍历新的关键帧的深度值的列
{
//std::cout << depth.ptr<short>(m)[n] << std::endl;
float d = 0;
if (depth.type() == CV_16U && depth.channels() == 1)
d = depth.ptr<short>(m)[n];//depth是一个opencv里的mat类型,使用指针进行遍历
else if (depth.type() == CV_32F && depth.channels() == 1)
d = depth.ptr<float>(m)[n];
else
continue;
if (d < 10 || d > 50000)//排除掉深度值过大或过小的点
continue;
if (_isnan(d))//排除nan值点
continue;
pcl::PointXYZ p;
p.z = d;
p.x = (n - cx) * p.z / fx;//cx,fx,fy是相机内参
p.y = (m - cy) * p.z / fy;//相当于把像素坐标转化为相机坐标
//p.b = imageRGB.ptr<uchar>(m)[n * 3];//保存每个点的rgb值
//p.g = imageRGB.ptr<uchar>(m)[n * 3 + 1];
//p.r = imageRGB.ptr<uchar>(m)[n * 3 + 2];
cloud->points.push_back(p);//将每个点保存到 PointCloud中的 points里面
}
}
总结
总结了下opencv对深度图常规操作,后续遇到新情况继续添加补充。