以TUM-RGB-D数据集为例
在rgbd_tum.cc中的main函数中,前面读取图片部分与ORB-SLAM2的代码基本一致。
根据传入的参数个数(argc的值),其算法的流程也会改变。
传入5个参数:就与普通的ORB-SLAM2无差别
传入6个参数:就会将MASK R-CNN得到的MASK图像存储到第6个参数的文件夹中,然后创建一个名为output的文件夹存储最后结果,其中存储Mask和去除动态物体后的depth和rgb图像。
传入7个参数:会将MASK图像存储到第6 个参数的文件夹中,将去除动态物体后的结果存到output文件夹中。
// Initialize Mask R-CNN
//进行Mask R-CNN初始化
DynaSLAM::SegmentDynObject *MaskNet;
if (argc==6 || argc==7)
{
cout << "Loading Mask R-CNN. This could take a while..." << endl;
//初始化一个语义分割的类
MaskNet = new DynaSLAM::SegmentDynObject();
cout << "Mask R-CNN loaded!" << endl;
}
接着看MaskNet.cc中的SegmentDynObject::SegmentDynObject()函数,这个函数的主要功能就是配置Python环境,初始化Python编译器,并将python文件中的类初始化。以便下一步使用Mask R-CNN进行语义分割。
SegmentDynObject::SegmentDynObject(){
std::cout << "Importing Mask R-CNN Settings..." << std::endl;
//传入Python相关的参数
ImportSettings();
std::string x;
//设置当前python的环境
setenv("PYTHONPATH", this->py_path.c_str(), 1);
x = getenv("PYTHONPATH");
//初始化Python编译器
Py_Initialize();
//cv::Mat与Python的np.array互相转换的函数
this->cvt = new NDArrayConverter();
this->py_module = PyImport_ImportModule(this->module_name.c_str());
assert(this->py_module != NULL);
this->py_class = PyObject_GetAttrString(this->py_module, this->class_name.c_str());
assert(this->py_class != NULL);
this->net = PyInstance_New(this->py_class, NULL, NULL);
assert(this->net != NULL);
std::cout << "Creating net instance..." << std::endl;
//生成一个空的mask空白RGB矩阵存放mask
cv::Mat image = cv::Mat::zeros(480,640,CV_8UC3); //Be careful with size!!
std::cout << "Loading net parameters..." << std::endl;
//在image中存储,0为静态物体,1为动态物体
GetSegmentation(image);
}
在DynaSLAM中是使用python进行语义分割,然后把前端语义分割部分与C++写的ORB-SLAM2结合起来的。
现在看传入Python相关参数的ImportSettings()函数,在MaskNet.cc文件中
void SegmentDynObject::ImportSettings(){
//string存储Python参数.yaml文件的地址
std::string strSettingsFile = "./Examples/RGB-D/MaskSettings.yaml";
//读取文件中的参数
cv::FileStorage fs(strSettingsFile.c_str(), cv::FileStorage::READ);
//Python文件的地址
fs["py_path"] >> this->py_path;
//模块的名称
fs["module_name"] >> this->module_name;
//类名
fs["class_name"] >> this->class_name;
//存储需要调用的python函数名称
fs["get_dyn_seg"] >> this->get_dyn_seg;
}
这个.yaml文件中的内容
Tips: 在C++中使用Python的一般过程
膨胀操作
在后面会对语义分割得到的Mask图像进行膨胀操作:
膨胀操作就是将属于动态物体的范围进一步扩大,因为在动态物体边缘的特征点也是无法使用的,会降低系统的精度。
Example:
进行膨胀操作的过程
// Dilation settings
//膨胀操作的核矩阵初始化
int dilation_size = 15;
//getStructuringElement函数来初始化,第一个参数为选择核的形状,这里选择的是椭圆形。第二参数为选择核的大小,第三个参数为选择核的中心点位置
cv::Mat kernel = getStructuringElement(cv::MORPH_ELLIPSE,
cv::Size( 2*dilation_size + 1, 2*dilation_size+1 ),
cv::Point( dilation_size, dilation_size ) );
/*
.......
......
*/
//maskRCNN数值在0~1之间,动态物体的mask对应的像素值为1
// Segment out the images
cv::Mat mask = cv::Mat::ones(480,640,CV_8U);
if (argc == 6 || argc == 7)
{
cv::Mat maskRCNN;
//GetSegmantation参数:RGB图像,Mask路径,图片保存名称
maskRCNN = MaskNet->GetSegmentation(imRGB,string(argv[5]),vstrImageFilenamesRGB[ni].replace(0,4,""));
cv::Mat maskRCNNdil = maskRCNN.clone();
//进行膨胀操作
cv::dilate(maskRCNN,maskRCNNdil, kernel);
//将原图与膨胀得到的相减,1表示静态物体
mask = mask - maskRCNNdil;
}