地图美化方案-房型图

0 阅读13分钟

Beautifi4 函数详细说明文档

文件

map_beautificaition/mapbeautifi.cpp

概述

Beautifi4 是地图美化算法中的一个重要函数,主要用于对SLAM生成的地图进行后处理优化。该函数通过轮廓检测、膨胀操作、最大内接矩形算法等技术,对地图进行智能美化处理,生成房型图。下面以一个例图展示每步的效果

image.png

函数签名

void MapBeauti::Beautifi4(uint8_t* map_data, int map_height, int map_width, int search_distance, int level)

参数说明

参数类型说明
map_datauint8_t*地图数据指针,存储像素值
map_heightint地图高度(像素行数)
map_widthint地图宽度(像素列数)
search_distanceint搜索距离参数(当前版本未使用)
levelint处理级别,影响最小矩形面积阈值,level越大越接近矩形

像素值含义

像素值含义说明
0黑色障碍物/墙壁
127灰色未知区域/边界
255白色自由空间
100家具值家具标记(furniture_value)

算法流程

1. 参数验证与初始化

// 安全检查
if (map_data == nullptr || map_height <= 0 || map_width <= 0) {
    return;
}
if (level <= 0) {
    level = 1; // 设置默认值
}

2. 膨胀操作

对灰色点(127)进行膨胀处理:

  • 如果灰色点的8连通邻域内有黑色点(0),则将该灰色点置为黑色
  • 重复执行2次以确保充分膨胀
for (int i = 0; i < 2; i++) {
    memcpy(tmp, map_data, map_height * map_width);
    for (int y = 0; y < map_height; ++y) {
        for (int x = 0; x < map_width; ++x) {
            if (tmp[y * map_width + x] == 127) {
                // 检查8连通邻域
                bool has_black = false;
                for (int dy = -1; dy <= 1 && !has_black; ++dy) {
                    for (int dx = -1; dx <= 1 && !has_black; ++dx) {
                        // 检查邻域内是否有黑色点
                    }
                }
                if (has_black) {
                    map_data[y * map_width + x] = 0;
                }
            }
        }
    }
}

3. 轮廓检测

使用 _ContourFinder 进行轮廓检测:

// 创建二值化图像
memset(tmp, 0, map_height * map_width);
for (int i = 0; i < map_height * map_width; i++) {
    if (map_data[i] == 127) {  // 灰色点
        tmp[i] = 0;
    } else {
        tmp[i] = 255;
    }
}

// 轮廓检测
_ContourFinder cf_binary;
cf_binary.Find((const int8_t*)tmp, map_width, map_height, map_width);
const auto& new_wall_contour = cf_binary.GetContours();

4. 选择最大轮廓

遍历所有检测到的轮廓,选择点数最多的轮廓作为主要处理对象:

_ContourFinder::Contour* contour = new_wall_contour->at(0);
int max_pt_size = contour->points.size();

for (size_t i = 0; i < new_wall_contour->size(); ++i) {
    if (new_wall_contour->at(i) != nullptr && 
        int32_t(new_wall_contour->at(i)->points.size()) > max_pt_size) {
        contour = new_wall_contour->at(i);
        max_pt_size = new_wall_contour->at(i)->points.size();
    }
}

image.png

5. 轮廓填充与边界处理

使用 DrawContourFill 函数填充轮廓内部,并处理轮廓边界:

// 填充轮廓
DrawContourFill(contour->points, tmp, 255, map_width, map_height);

// 轮廓外清除
for (int y = 0; y < map_height; ++y) {
    for (int x = 0; x < map_width; ++x) {
        if (tmp[y * map_width + x] != 255) {
            map_data[y * map_width + x] = 127;
        }
    }
}

// 轮廓边界处理
for (const auto& pt : contour->points) {
    // 将轮廓点周围7x7范围内的黑色点置为家具值
    for (int dy = -3; dy <= 3; ++dy) {
        for (int dx = -3; dx <= 3; ++dx) {
            // 边界检查和像素值修改
        }
    }
}

6. 外接矩形计算

计算轮廓的外接矩形,并在地图上绘制矩形边界:

// 计算外接矩形
int min_x = map_width, max_x = -1;
int min_y = map_height, max_y = -1;

for (int y = 0; y < map_height; y++) {
    for (int x = 0; x < map_width; x++) {
        if (tmp[y * map_width + x] == 255) {
            min_x = std::min(min_x, x);
            max_x = std::max(max_x, x);
            min_y = std::min(min_y, y);
            max_y = std::max(max_y, y);
        }
    }
}

// 绘制矩形边界
for (int x = min_x; x <= max_x; ++x) {
    map_data[min_y * map_width + x] = 0; // 上边
    map_data[max_y * map_width + x] = 0; // 下边
}
for (int y = min_y; y <= max_y; ++y) {
    map_data[y * map_width + min_x] = 0; // 左边
    map_data[y * map_width + max_x] = 0; // 右边
}

image.png

7. 最大内接矩形算法

使用单调栈算法寻找最大内接矩形:

int* height = new int[map_width];
int rect_area = (max_x - min_x + 1) * (max_y - min_y + 1);

// 根据矩形面积设置最小阈值
int min_rect_area = 0;
if(rect_area < 2000){
    min_rect_area = 50 * level;
} else if(rect_area < 10000){
    min_rect_area = 100 * level;
} else{
    min_rect_area = 300 * level;
}

// 单调栈算法寻找最大矩形
while (true) {
    memset(height, 0, sizeof(int) * map_width);
    
    for (int y = min_y; y <= max_y; ++y) {
        // 更新高度数组
        for (int x = min_x; x <= max_x; ++x) {
            if (tmp[y * map_width + x] == 255) {
                height[x] += 1;
            } else {
                height[x] = 0;
            }
        }
        
        // 单调栈处理
        std::vector<int> stack;
        // ... 单调栈算法实现
    }
    
    // 如果最大矩形面积小于阈值,退出循环
    if (max_area < min_rect_area) {
        break;
    }
    
    // 将最大矩形区域涂黑
    for (int y = max_top; y <= max_bottom; ++y) {
        for (int x = max_left; x <= max_right; ++x) {
            tmp[y * map_width + x] = 0;
            map_data[y * map_width + x] = 127;
        }
    }
}

image.png

image.png

image.png

8. 后处理

最后调用 process_gray_pointsprocess_black_points 进行最终的后处理:

process_gray_points(map_data, map_width, map_height);
process_black_points(map_data, map_width, map_height, true);

process_gray_points给所有的灰色点加上黑色边界

image.png process_black_points 去掉多余的黑边

image.png

关键特性

1. 安全性检查

  • 空指针检查
  • 参数有效性验证
  • 内存分配失败处理
  • 整数溢出保护

2. 自适应阈值

根据外接矩形面积动态调整最小矩形面积阈值:

  • 小面积区域(<2000):50 × level
  • 中等面积区域(<10000):100 × level
  • 大面积区域(≥10000):300 × level

3. 轮廓优化

  • 自动选择最大轮廓进行处理
  • 轮廓边界智能处理
  • 轮廓填充算法

4. 矩形检测

  • 使用单调栈算法高效寻找最大内接矩形
  • 迭代处理直到无法找到足够大的矩形
  • 动态更新处理区域

使用示例

// 创建地图数据
uint8_t* map_data = new uint8_t[height * width];
// ... 初始化地图数据

// 调用Beautifi4函数
MapBeauti::Beautifi4(map_data, height, width, 10, 2);

// 处理完成后的地图数据可用于后续应用

注意事项

  1. 内存管理:函数内部会分配临时内存,确保在函数结束时正确释放
  2. 参数范围:level 参数建议在1-5之间,过大的值可能导致过度处理
  3. 地图尺寸:建议地图尺寸不要过大,以避免内存问题
  4. 像素值:确保输入地图的像素值符合预期(0, 127, 255等)

性能考虑

  • 时间复杂度:O(n²),其中n为地图像素总数
  • 空间复杂度:O(n),主要用于临时数组存储
  • 主要瓶颈:轮廓检测和单调栈算法

扩展性

该函数设计具有良好的扩展性:

  • 可以通过修改 level 参数调整处理强度
  • 可以扩展支持不同的像素值含义
  • 可以集成更多的后处理算法

调用

关于beautifi函数的调用,位于 protocol/src/maps/navi_map_utils.cpp文件中的GetAPPShowMap中,在美化之后,需要特别处理扩展出来的区域,与IOT协议后需要做如下处理

  1. 扩展的区域与最邻近的分区ID保持一致

    1. 找出所有分区的边界线
    2. 找出期望的扩展区域轮廓。同时记录轮廓相邻的分区id
    3. 找出id对应的分界线
    4. 每个轮廓上的点判断位于分界线的哪一端从而置位
    void NaviMapUtils::EraseMosaic(MapData& map_data, const MapData& seg_map_data) {
        auto map_param = map_data.GetMapParam();
        uint8_t *map_data_ptr = map_data.GetMapDataPtr();
        int neighbor[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
    
        auto GetSlamIndex = [&](int y, int x) -> int { return y * map_param.width_ + x; };
        auto IsInSlamBound = [&](int slam_index) -> bool {
            return (slam_index >= 0 && slam_index < (map_param.height_ * map_param.width_));
        };
    
        // 一次性检测所有分区间的边界线并缓存
        std::map<std::pair<uint8_t, uint8_t>, std::vector<BoundaryLine>> cached_boundary_lines;
        
        // 一次遍历检测所有边界线
        // 检测水平边界线
        for (int y = 0; y < map_param.height_ - 1; y++) {
            int segment_start = -1;
            uint8_t current_region1 = 0, current_region2 = 0;
            
            for (int x = 0; x < map_param.width_; x++) {
                int upper_idx = GetSlamIndex(y, x);
                int lower_idx = GetSlamIndex(y + 1, x);
                
                if (IsInSlamBound(upper_idx) && IsInSlamBound(lower_idx)) {
                    uint8_t upper_region = map_data_ptr[upper_idx];
                    uint8_t lower_region = map_data_ptr[lower_idx];
                    
                    // 检查是否是边界(两个像素属于不同分区且都是有效分区)
                    if (upper_region != lower_region && 
                        upper_region >= 1 && upper_region <= 31 && 
                        lower_region >= 1 && lower_region <= 31) {
                        
                        if (segment_start == -1) {
                            // 开始新的边界线段
                            segment_start = x;
                            current_region1 = upper_region;
                            current_region2 = lower_region;
                        } else if (upper_region != current_region1 || lower_region != current_region2) {
                            // 结束当前线段(分区对发生变化)
                            auto key1 = std::make_pair(current_region1, current_region2);
                            auto key2 = std::make_pair(current_region2, current_region1);
                            BoundaryLine line(BoundaryLine::HORIZONTAL, y, segment_start, x - 1, current_region1, current_region2);
                            cached_boundary_lines[key1].push_back(line);
                            cached_boundary_lines[key2].push_back(line);
                            
                            // 开始新的线段
                            segment_start = x;
                            current_region1 = upper_region;
                            current_region2 = lower_region;
                        }
                    } else {
                        if (segment_start != -1) {
                            // 结束当前线段
                            auto key1 = std::make_pair(current_region1, current_region2);
                            auto key2 = std::make_pair(current_region2, current_region1);
                            BoundaryLine line(BoundaryLine::HORIZONTAL, y, segment_start, x - 1, current_region1, current_region2);
                            cached_boundary_lines[key1].push_back(line);
                            cached_boundary_lines[key2].push_back(line);
                            segment_start = -1;
                        }
                    }
                }
            }
            
            // 处理行末的线段
            if (segment_start != -1) {
                auto key1 = std::make_pair(current_region1, current_region2);
                auto key2 = std::make_pair(current_region2, current_region1);
                BoundaryLine line(BoundaryLine::HORIZONTAL, y, segment_start, map_param.width_ - 1, current_region1, current_region2);
                cached_boundary_lines[key1].push_back(line);
                cached_boundary_lines[key2].push_back(line);
            }
        }
        
        // 检测垂直边界线
        for (int x = 0; x < map_param.width_ - 1; x++) {
            int segment_start = -1;
            uint8_t current_region1 = 0, current_region2 = 0;
            
            for (int y = 0; y < map_param.height_; y++) {
                int left_idx = GetSlamIndex(y, x);
                int right_idx = GetSlamIndex(y, x + 1);
                
                if (IsInSlamBound(left_idx) && IsInSlamBound(right_idx)) {
                    uint8_t left_region = map_data_ptr[left_idx];
                    uint8_t right_region = map_data_ptr[right_idx];
                    
                    // 检查是否是边界(两个像素属于不同分区且都是有效分区)
                    if (left_region != right_region && 
                        left_region >= 1 && left_region <= 31 && 
                        right_region >= 1 && right_region <= 31) {
                        
                        if (segment_start == -1) {
                            // 开始新的边界线段
                            segment_start = y;
                            current_region1 = left_region;
                            current_region2 = right_region;
                        } else if (left_region != current_region1 || right_region != current_region2) {
                            // 结束当前线段(分区对发生变化)
                            auto key1 = std::make_pair(current_region1, current_region2);
                            auto key2 = std::make_pair(current_region2, current_region1);
                            BoundaryLine line(BoundaryLine::VERTICAL, x, segment_start, y - 1, current_region1, current_region2);
                            cached_boundary_lines[key1].push_back(line);
                            cached_boundary_lines[key2].push_back(line);
                            
                            // 开始新的线段
                            segment_start = y;
                            current_region1 = left_region;
                            current_region2 = right_region;
                        }
                    } else {
                        if (segment_start != -1) {
                            // 结束当前线段
                            auto key1 = std::make_pair(current_region1, current_region2);
                            auto key2 = std::make_pair(current_region2, current_region1);
                            BoundaryLine line(BoundaryLine::VERTICAL, x, segment_start, y - 1, current_region1, current_region2);
                            cached_boundary_lines[key1].push_back(line);
                            cached_boundary_lines[key2].push_back(line);
                            segment_start = -1;
                        }
                    }
                }
            }
            
            // 处理列末的线段
            if (segment_start != -1) {
                auto key1 = std::make_pair(current_region1, current_region2);
                auto key2 = std::make_pair(current_region2, current_region1);
                BoundaryLine line(BoundaryLine::VERTICAL, x, segment_start, map_param.height_ - 1, current_region1, current_region2);
                cached_boundary_lines[key1].push_back(line);
                cached_boundary_lines[key2].push_back(line);
            }
        }
    
        std::queue<std::pair<int, int>> queue;
        for (int slam_y = 0; slam_y < map_param.height_; slam_y++) {
            for (int slam_x = 0; slam_x < map_param.width_; slam_x++) {
                int offset_index = GetSlamIndex(slam_y, slam_x);
                if (IsInSlamBound(offset_index) && (map_data_ptr[offset_index] == 255 || map_data_ptr[offset_index] == FURNITURE_VALUE)) {
                    int detected_value = map_data_ptr[offset_index];
                    std::vector<std::pair<int, int>> contours;
                    std::queue<std::pair<int, int>> q;
                    std::pair<int, int> root(slam_x, slam_y);
                    contours.emplace_back(root);
                    q.push(root);
                    
                    // 收集相邻的分区ID
                    std::set<uint8_t> adjacent_regions;
                    
                    while (!q.empty()) {
                        std::pair<int, int> cur = q.front();
                        q.pop();
                        for (const auto &n : neighbor) {
                            int newX = cur.first + n[1];
                            int newY = cur.second + n[0];
                            int slam_offset_index = GetSlamIndex(newY, newX);
    
                            if (IsInSlamBound(slam_offset_index)) {
                                if (map_data_ptr[slam_offset_index] == detected_value) {
                                    std::pair<int, int> newPoint(newX, newY);
                                    contours.emplace_back(newPoint);
                                    q.push(newPoint);
                                    map_data_ptr[slam_offset_index] = detected_value == 255 ? 254 : 253;  // 临时标记
                                } else if (map_data_ptr[slam_offset_index] >= 1 && map_data_ptr[slam_offset_index] <= 31) {
                                    adjacent_regions.insert(map_data_ptr[slam_offset_index]);
                                }
                            }
                        }
                    }
                    // 将contours_furniture中的点合并到contours中
                    int white_contour_size = contours.size();
                    if (adjacent_regions.size() >= 1) {
                        if (adjacent_regions.size() == 1) {
                            // 只有一个相邻分区,直接分配
                            uint8_t region_id = *adjacent_regions.begin();
                            // 先处理普通contours
                            for (auto p : contours) {
                                int slam_offset_index = GetSlamIndex(p.second, p.first);
                                if (IsInSlamBound(slam_offset_index)) {
                                    map_data_ptr[slam_offset_index] = map_data_ptr[slam_offset_index] == 253 ? region_id + 32 : region_id;
                                }
                            }
                        } else {
                            // 多个相邻分区,使用几何位置签名匹配
                            std::vector<BoundaryLine> boundary_lines;
                            
                            // 从缓存中获取所有相关的边界线
                            std::vector<uint8_t> regions(adjacent_regions.begin(), adjacent_regions.end());
                            for (size_t i = 0; i < regions.size(); i++) {
                                for (size_t j = i + 1; j < regions.size(); j++) {
                                    auto key = std::make_pair(regions[i], regions[j]);
                                    auto it = cached_boundary_lines.find(key);
                                    if (it != cached_boundary_lines.end()) {
                                        const auto& lines = it->second;
                                        boundary_lines.insert(boundary_lines.end(), lines.begin(), lines.end());
                                    }
                                }
                            }
                            
                            // 为每个分区选择一个代表点
                            std::map<uint8_t, std::pair<int, int>> region_representatives;
                            for (uint8_t region : adjacent_regions) {
                                // 在连通域附近寻找该分区的代表点
                                bool found = false;
                                const int search_radius = 2;  // 固定搜索半径为2
                                for (auto& contour_point : contours) {
                                    for (int dy = -search_radius; dy <= search_radius && !found; dy++) {
                                        for (int dx = -search_radius; dx <= search_radius && !found; dx++) {
                                            if (dx == 0 && dy == 0) continue;
                                            
                                            int nx = contour_point.first + dx;
                                            int ny = contour_point.second + dy;
                                            int nidx = GetSlamIndex(ny, nx);
                                            
                                            if (IsInSlamBound(nidx) && map_data_ptr[nidx] == region) {
                                                region_representatives[region] = {nx, ny};
                                                found = true;
                                            }
                                        }
                                    }
                                }
                            }
                            
                            // 计算每个分区代表点的几何签名(相对于所有边界线的位置)
                            std::map<uint8_t, std::vector<int>> region_signatures;
                            for (const auto& pair : region_representatives) {
                                uint8_t region = pair.first;
                                auto rep_point = pair.second;
                                std::vector<int> signature;
                                for (const auto& line : boundary_lines) {
                                    // 计算代表点相对于边界线的位置
                                    if (line.type == BoundaryLine::HORIZONTAL) {
                                        if (rep_point.second <= line.coordinate) {
                                            signature.push_back(-1);  // 上方
                                        } else if (rep_point.second > line.coordinate) {
                                            signature.push_back(1);   // 下方
                                        } 
                                        // else {
                                        //     signature.push_back(0);   // 在线上
                                        // }
                                    } else {  // VERTICAL
                                        if (rep_point.first <= line.coordinate) {
                                            signature.push_back(-1);  // 左方
                                        } else if (rep_point.first > line.coordinate) {
                                            signature.push_back(1);   // 右方
                                        } 
                                        // else {
                                        //     signature.push_back(0);   // 在线上
                                        // }
                                    }
                                }
                                region_signatures[region] = signature;
                            }
                            
                            // 对连通域中的每个点进行分区分配
                            for (auto p : contours) {
                                int slam_offset_index = GetSlamIndex(p.second, p.first);
                                if (!IsInSlamBound(slam_offset_index)) {
                                    continue;
                                }
                                
                                if (boundary_lines.empty() || region_signatures.empty()) {
                                    // 回退到邻域投票
                                    std::vector<int> map_id_cnt(32, 0);
                                    for (const auto &n : neighbor) {
                                        int newX = p.first + n[1];
                                        int newY = p.second + n[0];
                                        int neighbor_index = GetSlamIndex(newY, newX);
                                        if (IsInSlamBound(neighbor_index)) {
                                            int tmp_id = map_data_ptr[neighbor_index];
                                            if (tmp_id >= 1 && tmp_id <= 31) {
                                                map_id_cnt[tmp_id]++;
                                            }
                                        }
                                    }
                                    
                                    uint8_t best_region = 0;
                                    int max_count = 0;
                                    for (uint8_t region : adjacent_regions) {
                                        if (map_id_cnt[region] > max_count) {
                                            max_count = map_id_cnt[region];
                                            best_region = region;
                                        }
                                    }
                                    
                                    if (best_region >= 1 && best_region <= 31) {
                                        if(map_data_ptr[slam_offset_index] == 253) {
                                            map_data_ptr[slam_offset_index] = best_region + 32;
                                        } else {
                                            map_data_ptr[slam_offset_index] = best_region;
                                        }
                                    }
                                } else {
                                    // 计算当前点的几何签名
                                    std::vector<int> point_signature;
                                    for (const auto& line : boundary_lines) {
                                        if (line.type == BoundaryLine::HORIZONTAL) {
                                            if (p.second <= line.coordinate) {
                                                point_signature.push_back(-1);  // 上方
                                            } else if (p.second > line.coordinate) {
                                                point_signature.push_back(1);   // 下方
                                            } 
                                            // else {
                                            //     point_signature.push_back(0);   // 在线上
                                            // }
                                        } else {  // VERTICAL
                                            if (p.first <= line.coordinate) {
                                                point_signature.push_back(-1);  // 左方
                                            } else if (p.first > line.coordinate) {
                                                point_signature.push_back(1);   // 右方
                                            } 
                                            // else {
                                            //     point_signature.push_back(0);   // 在线上
                                            // }
                                        }
                                    }
                                    
                                    // 寻找几何签名匹配的分区
                                    uint8_t best_region = 0;
                                    int max_matches = -1;
                                    
                                    for (const auto& pair : region_signatures) {
                                        uint8_t region = pair.first;
                                        const auto& signature = pair.second;
                                        if (signature.size() != point_signature.size()) continue;
                                        
                                        int matches = 0;
                                        for (size_t i = 0; i < signature.size(); i++) {
                                            if (signature[i] == point_signature[i]) {
                                                matches++;
                                            }
                                        }
                                        
                                        if (matches > max_matches) {
                                            max_matches = matches;
                                            best_region = region;
                                        }
                                    }
                                    
                                    // 如果没有找到好的匹配,回退到邻域投票
                                    if (best_region == 0 || max_matches < static_cast<int>(boundary_lines.size() / 2)) {
                                        std::vector<int> map_id_cnt(32, 0);
                                        for (const auto &n : neighbor) {
                                            int newX = p.first + n[1];
                                            int newY = p.second + n[0];
                                            int neighbor_index = GetSlamIndex(newY, newX);
                                            if (IsInSlamBound(neighbor_index)) {
                                                int tmp_id = map_data_ptr[neighbor_index];
                                                if (tmp_id >= 1 && tmp_id <= 31) {
                                                    map_id_cnt[tmp_id]++;
                                                }
                                            }
                                        }
                                        
                                        int max_count = 0;
                                        for (uint8_t region : adjacent_regions) {
                                            if (map_id_cnt[region] > max_count) {
                                                max_count = map_id_cnt[region];
                                                best_region = region;
                                            }
                                        }
                                    }
                                    
                                    if (best_region >= 1 && best_region <= 31) {
                                        if(map_data_ptr[slam_offset_index] == 253) {
                                            map_data_ptr[slam_offset_index] = best_region + 32;
                                        } else {
                                            map_data_ptr[slam_offset_index] = best_region;
                                        }
                                    }
                                }
                            }
                        }
                    } else if (contours.size() < 400 && detected_value == 255) {
                        for (auto p : contours) {
                            int slam_offset_index = GetSlamIndex(p.second, p.first);
                            if (IsInSlamBound(slam_offset_index)) {
                                map_data_ptr[slam_offset_index] = 127;
                            }
                        }
                    }
                }
            }
        }
    
        // 恢复临时标记
        for (int slam_y = 0; slam_y < map_param.height_; slam_y++) {
            for (int slam_x = 0; slam_x < map_param.width_; slam_x++) {
                int offset_index = GetSlamIndex(slam_y, slam_x);
                if (IsInSlamBound(offset_index)) {
                    if(map_data_ptr[offset_index] == 254) {
                        map_data_ptr[offset_index] = 255;
                    } else if(map_data_ptr[offset_index] == 253) {
                        map_data_ptr[offset_index] = FURNITURE_VALUE;
                    }
                }
    
                if (IsInSlamBound(offset_index) && map_data_ptr[offset_index] == 127) {
                    for (int i = 0; i < 8; i++) {
                        int tmp_y = slam_y + neighbor[i][0];
                        int tmp_x = slam_x + neighbor[i][1];
                        int tmp_offset_index = GetSlamIndex(tmp_y, tmp_x);
                        if (IsInSlamBound(tmp_offset_index) && map_data_ptr[tmp_offset_index] > 0 &&
                            map_data_ptr[tmp_offset_index] <= 31) {
                            map_data_ptr[tmp_offset_index] = 0;
                            break;
                        }
                    }
                }
            }
        }
    }
    
  2. 需要在高位置1来表示扩展区域,因为分区id为1-31,所以检测到的扩展分区应该等于32 + id