Bootstrap

c++ 实现 prm

文章目录

1. 代码

采样 + 搜索,这里搜索用的就是 dijkstra, 用 Astar 也可以

#include <iostream>
#include <vector>
#include <string>
#include <queue>

#include "opencv2/highgui.hpp"
#include "opencv2/opencv.hpp"

// #include <direct.h> 
#include <unistd.h> //目录
#include <typeinfo>

#define INF  13421772
#define sampleNum 200
#define START  0
#define GOAL   1

double toDegree(double radian) {return radian * 180 / M_PI;}

double toRadian(double degree) {return degree * M_PI / 180;}

struct GraphNode{
    int label;
    std::vector<GraphNode*> neighbors;
    GraphNode(int x): label(x) {};
};

void loadMap(){
    // char *root_path = NULL;
    // root_path = getcwd(NULL,0);
    // std::cout << root_path << std::endl;
    // cv::Mat dismap = cv::imread("../map/map_2.bmp");
    // cv::imshow("dismap", dismap);
    // cv::waitKey(1000);
}

bool checkCollision(const std::vector<int> point, const cv::Mat map){
    bool reach = true;
    if(map.at<cv::Vec3b>(point[1],point[0])[0]==0 && 
       map.at<cv::Vec3b>(point[1],point[0])[1]==0 && 
       map.at<cv::Vec3b>(point[1],point[0])[2]==0){
           reach = false;
       }

    return reach;
}

//这里只是设置了10个点,也可以根据间距最大的设置采样点
bool checkPath(const std::vector<int> point_a, 
               const std::vector<int> point_b, 
               const cv::Mat map, int split_num){
    
    std::vector<double> path_x;
    std::vector<double> path_y;
    // path_x.reserve(split_num + 1);
    // path_y.reserve(split_num + 1);

    // int min_x = point_a[0] > point_b[0] ? point_a[0] : point_b[0];
    // int min_y = point_a[1] > point_b[1] ? point_a[1] : point_b[1];
    double interval_x = (point_b[0] - point_a[0]) / (split_num);
    double interval_y = (point_b[1] - point_a[1]) / (split_num);

    // std::cout << point_a[0] << "," << point_b[0] << std::endl;

    for(int i = 0; i <= split_num; ++i){
        path_x.push_back(point_a[0] + i * interval_x);
        path_y.push_back(point_a[1] + i * interval_y);
        // std::cout << point_a[0] + i * interval_x << "," << point_a[1] + i * interval_y << std::endl;
        // std::cout << "i:" << i << std::endl;
    }

    for(int i = 0; i <= split_num; ++i){
        if(!checkCollision({int(path_x[i]), int(path_y[i])}, map)){
            return false;
        }
    }

    return true;
}

double calcDistance(const std::vector<int> point_a, const std::vector<int> point_b){
    return sqrt(pow(point_a[0]-point_b[0],2) + pow(point_a[1]-point_b[1],2));
}

struct Dijkstra {
    struct node{
        int point;
        double value;
        node(int _point, double _value):point(_point), value(_value){}
        bool operator < (const node& rhs) const{
                return value > rhs.value;
        }
    };

    std::vector<node> edges[sampleNum];
    double dist[sampleNum];
    int path[sampleNum];

    void init()
	{
		for(int i = 0; i < sampleNum; i++)
        {
            edges[i].clear();
            dist[i] = 0;
            path[i] = 0;
        }
	}

    void addEdge(int from, int to, double dist)
	{
		edges[from].push_back(node(to,dist));
        // edges[to].push_back(node(from,dist));
	}

    void showEdge()
    {
        std::cout << "------------------------" << std::endl;

        for(int i = 0; i< sampleNum; i++)
        {
            // cout << "-----" << i << "-----" << endl;

            for(int j=0; j<edges[i].size(); j++)
            {
                std::cout << i << "," << edges[i][j].point << "," << edges[i][j].value << std::endl;
            }

            // cout << "**********************" << endl;

        }

        std::cout << "------------------------" << std::endl;
    }

    std::vector<int> dijkstra(int s, int t)
	{
		std::priority_queue <node> q;

		for(int i = 0; i < sampleNum; i++)
            dist[i] = INF;

		dist[s] = 0;
		q.push(node(s, dist[s]));

		while(!q.empty())
		{
            node x = q.top(); q.pop();
            for (int i = 0; i < edges[x.point].size(); i++)
            {
                // std::cout << edges[x.point].size() << std::endl;
                node y = edges[x.point][i];
                if (dist[y.point] > dist[x.point] + y.value)
                {
                    dist[y.point] = dist[x.point] + y.value;
                    path[y.point] = x.point;
                    q.push(node(y.point, dist[y.point]));
                }
            }
		}

        std::vector<int> result;

        // 存距离
        // result.push_back(dist[t]);
        std::cout << "dist[t]:" << dist[t] << std::endl;

        while(t)
        {
            result.push_back(t);
            t = path[t];
        }
        
        result.push_back(path[0]);


        reverse(result.begin(),result.end()); //起点->终点 ,+ 距离

        // for show result (start -> end,cost)
        // for(int i=0; i < result.size(); i++)
        // {
        //     std::cout << result[i] << " ";
        // }

        return result;
    }
};

struct Dijkstra DijkstraPlanning;  

int main() {

    cv::Mat dismap = cv::imread("../map/map_2.bmp");
    // cv::imshow("dismap", dismap);
    // cv::waitKey(1000);
    int mapLength = dismap.cols;
    int mapWidth = dismap.rows; 

    // std::cout << "mapLength:" << mapLength << ",mapWidth:" << mapWidth << std::endl;
    // std::cout << dismap.size[0] << typeid(dismap.size).name() << std::endl;


    //改为结构体
    // std::vector<int> pStrat = {50, 50};
    // std::vector<int> pGoal = {450, 450};

    std::vector<int> pStrat = {10, 10};
    std::vector<int> pGoal = {490, 490};

    std::vector<std::vector<int> > sampleMap;
    sampleMap.reserve(sampleNum + 2);
    sampleMap.push_back(pStrat);
    sampleMap.push_back(pGoal);

    // std::cout << sampleMap.size() << std::endl;

    //初始化采样点
    while (sampleMap.size() < sampleNum + 2)
    // while (sampleMap.size() < 10)
    {

        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(0, dismap.size[0]-1);
        
        
        std::vector<int> res;
        // sampleMap.push_back(std::vector<int>());
        for(int i=0; i<2; ++i){
            res.push_back(dis(gen));
            // sampleMap.back().push_back(dis(gen));
        }

        if(checkCollision(res, dismap)){
            sampleMap.push_back({res[0], res[1]});
        }
        
        // std::cout << res[0] << "," << res[1] << std::endl;
    }

    const int MAX_N = sampleNum + 2;
    GraphNode *Graph[MAX_N];

    const double DISTANCE = 100; 
    const int SPLIT_N = 10;
    
    // for(int i = 0; i < MAX_N; i++){
    //     Graph[i] = new GraphNode(i);
    // }

    DijkstraPlanning.init();

    for (int i = 0; i < MAX_N; i++)
    {
        for(int j = 0; j < MAX_N; j++){
            if (calcDistance(sampleMap[i], sampleMap[j]) <= DISTANCE && 
                checkPath(sampleMap[i], sampleMap[j], dismap, SPLIT_N) && i!= j)
            {
                cv::line(dismap, cv::Point(sampleMap[i][0], sampleMap[i][1]), 
                                 cv::Point(sampleMap[j][0], sampleMap[j][1]), 
                                 cv::Scalar(0, 0, 255), 1);
                // Graph[i]->neighbors.push_back(Graph(i));

                DijkstraPlanning.addEdge(i, j, calcDistance(sampleMap[i], sampleMap[j]));
            }
            
        }
    }

    // for(int i=0; i<sampleMap.size(); i++){
    //     // std::cout << i << ":";
    //     for(int j=0; j<sampleMap[i].size(); j++){
    //         // std::cout << sampleMap[i][j] << ",";
    //        std::cout << sampleMap[i][j] << ",";

    //     }
    //     std::cout << std::endl;
    // }
    
    DijkstraPlanning.showEdge();


    std::vector<int> result = DijkstraPlanning.dijkstra(START, GOAL);
    // std::cout << "result.size(): " << result.size() << std::endl;

    // std::cout << "result: ";

    // for(int i=0; i < result.size(); i++)
    // {
    //     std::cout << result[i] << " ";
    // }

    if(result.size() > 2){
        for(int i=0;i < result.size() - 1; i++)
        {
            // std::cout << result[i] << " ";
            cv::line(dismap, cv::Point(sampleMap[result[i]][0], sampleMap[result[i]][1]), 
                    cv::Point(sampleMap[result[i+1]][0], sampleMap[result[i+1]][1]), 
                    cv::Scalar(0, 255, 0), 5);
        }
    }

    for(int i=0; i<sampleMap.size(); i++){
        // std::cout << i << ":";
        for(int j=0; j<sampleMap[i].size(); j++){
            // std::cout << sampleMap[i][j] << ",";
            dismap.at<cv::Vec3b>(sampleMap[i][1],sampleMap[i][0])[0] = 0;
            dismap.at<cv::Vec3b>(sampleMap[i][1],sampleMap[i][0])[1] = 255; 
            dismap.at<cv::Vec3b>(sampleMap[i][1],sampleMap[i][0])[2] = 0;

        }
        // std::cout << std::endl;
    }
    
    // std::cout << sampleMap.size() << std::endl;

    cv::imshow("dismap", dismap);
    cv::waitKey(10000);
    
    // if(result.size() > 2){
    //     cv::imwrite("/home/seivl/me/代码/规划/prm/planning_result/prm.bmp", dismap);
    // }
    
  return 0;
}

2. 结果

在这里插入图片描述

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;