问题介绍
本问是实际扫地机器人对于2D激光SLAM采用cartographer所建的地图中,可以看到边缘处有噪点,从而影响了地图在app端的图片效果,针对这个问题,产生了两种解决的思路:
方法一:直接从建图的图片入手,运用数字图像处理的方法处理地图。
方法二:从cartographer源码处优化边缘的噪点,对噪点进行剔除。
本文主要采用了方法一,并随研究更新,同时学习开始研究方法二的实现。
实现步骤
- 图片输入为三通道RGB图,首先进行图片灰度化处理 ;
- 对灰度图像(单通道)进行高斯滤波,滤波后的模糊图片;
- 对滤波后的图片采用canny算子进行边缘检测;
- 检测后图像恢复3通道,并显示在原图像中;
- 阈值判断,以边缘为分界,边缘处更新相关灰度,边缘外的噪点与原地图外的灰度保持一致,其余灰度不变;
代码实现
#include <iostream>
#include <chrono>
using namespace std;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main ( int argc, char** argv )
{
// 读取argv[1]指定的图像
cv::Mat image;
image = cv::imread ( "/home/figure.pgm" ); //cv::imread函数读取指定路径下的图像
// 判断图像文件是否正确读取
if ( image.data == nullptr ) //数据不存在,可能是文件不存在
{
cerr<<"文件"<<argv[1]<<"不存在."<<endl;
return 0;
}
// 文件顺利读取, 首先输出一些基本信息,图像尺度信息
cout<<"原图像宽为"<<image.cols<<",高为"<<image.rows<<",通道数为"<<image.channels()<<endl;
cv::imshow ( "image", image ); // 用cv::imshow显示图像
cv::waitKey ( 0 ); // 暂停程序,等待一个按键输入
//1.灰度图转换,默认的色彩空间是BGR
cv::Mat srcGray;
cvtColor(image, srcGray, CV_BGR2GRAY);
imshow("srcGray", srcGray);
cout<<"灰度图像宽为"<<srcGray.cols<<",高为"<<srcGray.rows<<",通道数为"<<srcGray.channels()<<endl;
cv::waitKey ( 0 ); // 暂停程序,等待一个按键输入
//2.对灰度图像进行高斯滤波
cv::Mat Gaus3_image;
GaussianBlur(srcGray,Gaus3_image,Size(3,3),2);
imshow("Gaus3_image",Gaus3_image);
cout<<"高斯滤波图像宽为"<<Gaus3_image.cols<<",高为"<<Gaus3_image.rows<<",通道数为"<<Gaus3_image.channels()<<endl;
cv::waitKey ( 0 ); // 暂停程序,等待一个按键输入
//3.canny算子检测边缘
cv::Mat Can_image;
std::vector<Vec4i> lines; //定义数组获取直线
cv::Canny(Gaus3_image,Can_image,200,350);
imshow("srcGray_line",Can_image);
cout<<"canny算子提线图像宽为"<<Can_image.cols<<",高为"<<Can_image.rows<<",通道数为"<<Can_image.channels()<<endl;
cv::waitKey ( 0 );
// 4.检测后图像恢复3通道,并显示在原图像中
cv::Mat dst,image1;
dst = Scalar::all(0);
image1 = image.clone();
image1.copyTo(dst,Can_image);
imshow("image_line",dst);
cv::waitKey ( 0 );
cv::Mat image2;
image2 = image-dst;
imshow("image2",image2);
cv::waitKey ( 0 );
// 5.遍历图片,阈值判断
for ( int i = 0; i < image2.rows; i++ )
{
for ( int j=0; j<image2.cols; j++ )
{
if(image2.at<Vec3b>(i,j)[0]==image2.at<Vec3b>(i,j)[1] && image2.at<Vec3b>(i,j)[0]==image2.at<Vec3b>(i,j)[2])
{
if(image2.at<Vec3b>(i,j)[0]>=0 && image2.at<Vec3b>(i,j)[0]<=55)
image2.at<Vec3b>(i,j)[0]=image2.at<Vec3b>(i,j)[1]=image2.at<Vec3b>(i,j)[2]=0;
else if(image2.at<Vec3b>(i,j)[0]>55 && image2.at<Vec3b>(i,j)[0]<170)
image2.at<Vec3b>(i,j)[0]=image2.at<Vec3b>(i,j)[1]=image2.at<Vec3b>(i,j)[2]=128;
else
image2.at<Vec3b>(i,j)[0]=image2.at<Vec3b>(i,j)[1]=image2.at<Vec3b>(i,j)[2];
}
}
}
imshow("image3",image2);
cout<<"imag2_f"<<Can_image.cols<<endl;
cv::waitKey ( 0 );
cv::destroyAllWindows();
return 0;
}
效果
参考文章
canny边缘检测
[1]:https://blog.csdn.net/zhmxy555/article/details/25560901
[2]:https://blog.csdn.net/qq78442761/article/details/54313569
[3]:https://blog.csdn.net/weicao1990/article/details/54570903
[4]:https://blog.csdn.net/MoreWindows/article/details/8239625
霍夫变换检测直线
[5]:https://blog.csdn.net/viewcode/article/details/8090932
[6]:https://cloud.tencent.com/developer/article/1470624
[7]:https://www.geek-share.com/detail/2713436600.html
[8]:https://blog.csdn.net/hzq20081121107/article/details/9287941
高斯滤波
[9]:https://www.cnblogs.com/hugochen1024/p/12864055.html#%E5%8F%8C%E8%BE%B9%E6%BB%A4%E6%B3%A2bilateral-filter
[10]:视觉SLAM十四讲5讲
[11]:思岚科技https://www.slamtec.com/en/News/Detail/389
[12]:思岚科技https://zhuanlan.zhihu.com/p/35202710