Morphological Segmentation 形态分割
算法的优点是:实现简单和计算速度快
算法实现效果:
算法实现大致描述:
- 步骤1:创建地图的副本,用于形态学操作。
- 步骤2:通过多次腐蚀操作来提取地图上的轮廓。
- 步骤3:找到腐蚀后的地图中的轮廓,并检查这些轮廓是否满足房间面积的标准。
- 步骤4:在原始地图的副本上绘制并填充符合条件的轮廓。
- 步骤5:从原始地图中提取障碍物信息,并在步骤4中创建的地图副本上绘制这些障碍物。
- 步骤6:将彩色区域扩展到白色像素,以完成分割。
主要对应函数
void MorphologicalSegmentation::segmentMap(const cv::Mat& map_to_be_labeled, cv::Mat& segmented_map, double map_resolution_from_subscription,double room_area_factor_lower_limit, double room_area_factor_upper_limit)关键代码1:对当前地图进行腐蚀操作,temporary_map_to_find_rooms为输入的待处理地图,在每一次腐蚀操作后更新
cv::Mat eroded_map;cv::Point anchor(-1, -1); //needed for opencv erodecv::erode(temporary_map_to_find_rooms, eroded_map, cv::Mat(), anchor, 1);关键代码2:在腐蚀后的地图上找到轮廓; temporary_contours:用于临时存储找到的轮廓。每个轮廓由一系列点(cv::Point)组成。 hierarchy:用于存储轮廓之间的层次关系。这包括每个轮廓的父轮廓、子轮廓、同级轮廓等信息。 CV_RETR_CCOMP参数指定检索模式,这里用于检索所有的轮廓并分类为外轮廓和内轮廓。 CV_CHAIN_APPROX_SIMPLE参数指定轮廓点的近似方法,这里用于压缩水平、垂直和对角线段。
cv::Mat contour_map = eroded_map.clone();std::vector < std::vector > temporary_contours; //temporary saving-variablestd::vector < cv::Vec4i > hierarchy;cv::findContours(contour_map, temporary_contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);关键代码3:找到轮廓后识别出符合特定条件的房间 检查轮廓数量:首先检查temporary_contours中是否有轮廓。如果没有,就不需要进一步处理。 遍历每个轮廓:对于temporary_contours中的每个轮廓,检查它是否满足作为房间的条件。 层次关系检查:使用hierarchy数组来确定当前轮廓是否是第一层轮廓(即主轮廓)。如果当前轮廓是第一层轮廓(hierarchy[current_contour][3] == -1),则继续处理。 计算轮廓面积:计算当前轮廓的面积,并考虑内部空洞(如果有)的面积。这是通过遍历所有轮廓并减去属于当前轮廓的内部空洞的面积来实现的。 面积判断:根据预设的面积限制(room_area_factor_lower_limit和room_area_factor_upper_limit),判断当前轮廓是否可以被视为一个房间。 保存和标记轮廓:如果当前轮廓满足房间的条件,将其保存到saved_contours中,并在原始地图上标记该轮廓(使用cv::drawContours)。
if (temporary_contours.size() != 0){ for (int current_contour = 0; current_contour < temporary_contours.size(); current_contour++) { if (hierarchy[current_contour][3] == -1) { double room_area = map_resolution_from_subscription * map_resolution_from_subscription* cv::contourArea(temporary_contours[current_contour]); for (int hole = 0; hole < temporary_contours.size(); hole++) { if (hierarchy[hole][3] == current_contour) { room_area -= map_resolution_from_subscription * map_resolution_from_subscription * cv::contourArea(temporary_contours[hole]); } } if (room_area_factor_lower_limit < room_area && room_area < room_area_factor_upper_limit) { saved_contours.push_back(temporary_contours[current_contour]); cv::drawContours(temporary_map_to_find_rooms, temporary_contours, current_contour, cv::Scalar(0), CV_FILLED, 8, hierarchy, 2); } } }}main中需要理解的部分: 补充:理解这部分了,就是说本身分割后的地图segmented_map由label构成,但是我现在创建一个indexed_map,存储和地图大小一样,但是每个地图位置上的值是房间编号(1-房间总数),需要配合label_vector_index_codebook生成函数进行使用;
cv::Mat indexed_map = segmented_map.clone();for (int x = 0; x < segmented_map.rows; ++x){ for (int y = 0; y < segmented_map.cols; ++y) { const int label = segmented_map.at(x, y); if (label > 0 && label < 65280) indexed_map.at(x, y) = label_vector_index_codebook[label] + 1; }}后续需要完成的工作 / 思考的内容:
-
√ 如何在代码中区分各个房间(需查看indexed_map的实现方式)
-
√ 如何对房间进行排序(需查看indexed_map的实现方式)
-
如何确定单个房间的起点和终点(房间口)
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时