描述

关于A_算法的一些实现,我已经写在了我的博客里。这里也贴出链接来,大家可以去看
[移动机器人路径规划算法及思考——A_算法](https://www.guyuehome.com/32775 “移动机器人路径规划算法及思考——A*算法”)

这篇我主要使用C++来实现了一下,发在这里,有一些代码写的还是不太优,以后会花些时间来优化的。

代码

代码分为三个文件,main.cpp,AStar.h头文件和AStar.cpp方法实现

我直接贴在下面

main.cpp

#include "AStar.h"
#include <iostream>
 
int main(int argc, char** argv)
{
    AStar astar;
    astar.set_mapPath("/Users/admin/Desktop/CodeBase/c++_try/map.jpeg");
    astar.set_startPoint(267, 281);
    astar.set_endPoint(968, 285);
 
    astar.search_path();
 
    return 0;
}

AStar.h

#ifndef __ASTAR_H__
#define __ASTAR_H__
#include <iostream>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <string>
#include "stdlib.h"
 
typedef struct Node
{
    int x, y;
    int f, g, h;
    Node *father;
    Node(int x, int y)
    {
        this->x = x;
        this->y = y;
        this->f = 0;
        this->g = 0;
        this->h = 0;
        this->father = NULL;
    };    
}Node;
 
class AStar
{
    public:
        AStar();
        ~AStar();
 
    public:
        void set_mapPath(std::string map_path);
        void set_startPoint(int x, int y);
        void set_endPoint(int x, int y);
 
        bool search_path();
 
        void add_around();
        void add_around_singleDirection(int x, int y);
 
        bool check_node_mapRange(int x, int y);
        bool check_node_free(int x, int y);
 
        double compute_g(int x, int y);
        double compute_h(int x, int y);
 
        int check_openList(int x, int y);
        int check_closedList(int x, int y);
        void sort_openList();
        void quickSort(int left, int right, std::vector<Node*>& arr);
 
        void draw_map();
        void draw_path(Node *node);
        void clear_memory();
        void draw_online();
 
        std::string m_map_path;
        cv::Mat m_map_whole_color;
        cv::Mat m_map_whole_gray;
        int m_map_row, m_map_col;
 
        Node* m_start_node;
        Node* m_end_node;
        Node* m_current_node;
 
        std::vector<Node*> m_open_list;
        std::vector<Node*> m_closed_list;
 
        double m_weight_x = 1;
        double m_weight_y = 1;
        double m_weight_diagonal = sqrt(2);
 
};
 
#endif

AStar.cpp

#include "AStar.h"
 
AStar::AStar()
{
 
}
 
AStar::~AStar()
{
 
}
 
void AStar::set_mapPath(std::string map_path)
{
    m_map_path = map_path;
    m_map_whole_color = cv::imread(m_map_path, cv::IMREAD_COLOR);
    m_map_whole_gray = cv::imread(m_map_path, cv::IMREAD_GRAYSCALE); 
    if( m_map_whole_gray.empty())                     
    {
        std::cout <<  "Could not open or find the image" << std::endl;
    }
 
    m_map_row = m_map_whole_gray.size().width;
    m_map_col = m_map_whole_gray.size().height;
 
}
 
void AStar::set_startPoint(int x, int y)
{
    m_start_node = new Node(x, y);
}
 
void AStar::set_endPoint(int x, int y)
{
    m_end_node = new Node(x, y);
}
 
bool AStar::search_path()
{
    if (m_start_node->x < 0 || m_start_node->x > m_map_row 
    || m_start_node->y < 0 || m_start_node->y >m_map_col
    || m_end_node->x < 0 || m_end_node->x > m_map_row 
    || m_end_node->y < 0 || m_end_node->y >m_map_col)
    {
        std::cout<<"start/end point is out of the map range"<<std::endl;
        return false;
    }
 
    m_current_node = m_start_node;
    m_open_list.push_back(m_start_node);
 
    while(m_open_list.size() > 0)
    {
        m_current_node = m_open_list[0];
 
        add_around();
 
        m_closed_list.push_back(m_current_node);
        m_open_list.erase(m_open_list.begin());
 
        sort_openList();
 
        // draw_online();
 
        if (m_current_node->x == m_end_node->x && m_current_node->y == m_end_node->y)
        {
            draw_path(m_current_node);
            clear_memory();
 
            std::cout<<"Find path successful"<<std::endl;
            return true;
        }
    }
    return false;
}
 
void AStar::add_around()
{
    add_around_singleDirection(m_current_node->x - 1, m_current_node->y - 1); // left up corner
    add_around_singleDirection(m_current_node->x    , m_current_node->y - 1); // up 
    add_around_singleDirection(m_current_node->x + 1, m_current_node->y - 1); // right up corner
    add_around_singleDirection(m_current_node->x - 1, m_current_node->y    ); // left 
    add_around_singleDirection(m_current_node->x + 1, m_current_node->y    ); // right
    add_around_singleDirection(m_current_node->x - 1, m_current_node->y + 1); // left down corner
    add_around_singleDirection(m_current_node->x    , m_current_node->y + 1); // down
    add_around_singleDirection(m_current_node->x + 1, m_current_node->y + 1); // right down corner
}
 
void AStar::add_around_singleDirection(int x, int y)
{    
    if (!check_node_mapRange(x, y))
        return ;
    if (!check_node_free(x, y))
        return ;
    if (check_closedList(x, y) != -1)
        return ;
 
    double g_new = m_current_node->g + compute_g(x, y);
 
    int id = check_openList(x, y);
 
    if (id != -1)
    {
        Node* node_old = m_open_list[id];
        if (g_new < node_old->g)
        {
            node_old->g = g_new;
            node_old->f = node_old->g + node_old->h;
            node_old->father = m_current_node;    
        }
    }
    else
    {
        Node* node_new = new Node(x, y);
        node_new->g = g_new;
        node_new->h = compute_h(x, y);
        node_new->f = node_new->g + node_new->h;
        node_new->father = m_current_node;
        m_open_list.push_back(node_new);
    }
}
 
int AStar::check_openList(int x, int y)
{
    int num = m_open_list.size();
    for (int i = 0 ; i < num; i++)
    {
        if (x == m_open_list[i]->x && y == m_open_list[i]->y)
            return i;
    }
    return -1;
}
 
int AStar::check_closedList(int x, int y)
{
    int num = m_closed_list.size();
    for (int i = 0 ; i < num; i++)
    {
        if (x == m_closed_list[i]->x && y == m_closed_list[i]->y)
            return i;
    }
    return -1;
}
 
bool AStar::check_node_mapRange(int x, int y)
{
    if ( x < 0 || x > m_map_row 
    || y < 0 || y > m_map_col)
    {
        return false;
    }
    return true;
}
 
bool AStar::check_node_free(int x, int y)
{
    int color = m_map_whole_gray.at<uchar>(y,x);
    if (color > 250)
        return true;
    else
        return false;
}
 
double AStar::compute_g(int x, int y)
{
    double g = 0;
    if (abs(x - m_current_node->x)+ abs(y - m_current_node->y) == 2)
    {
        g = m_weight_diagonal;
    }
    if (abs(x - m_current_node->x) == 0 )
    {
        g = m_weight_y; 
    }
    if (abs(y - m_current_node->y) == 0 )
    {
        g = m_weight_x;
    }
    return g;
}
 
double AStar::compute_h(int x, int y)
{
    double h = sqrt(pow(x - m_end_node->x, 2) + pow(y - m_end_node->y, 2));
    return h;
}
 
 
void AStar::sort_openList()
{
    std::vector<double> f_list;
    quickSort(0, m_open_list.size()-1, m_open_list);
}
 
void AStar::quickSort(int left, int right, std::vector<Node*>& arr)
{
    if(left >= right)
        return;
    int i, j;
    Node* base = arr[left];
    i = left, j = right;
    base = arr[left];
    while (i < j)
    {
        while (arr[j]->f >= base->f && i < j)
            j--;
        while (arr[i]->f <= base->f && i < j)
            i++;
        if(i < j)
        {
            Node* temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    arr[left] = arr[i];
    arr[i] = base;
    quickSort(left, i - 1, arr);
    quickSort(i + 1, right, arr);
}
 
 
void AStar::draw_map()
{
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", m_map_whole_color );
    cv::waitKey(0);
}
 
void AStar::draw_path(Node *node)
{
    if (node->father != NULL)
    {
        cv::circle(m_map_whole_color, cv::Point((int)(node->x), (int)(node->y)), 1, cv::Scalar(0, 0, 255), -1);
        draw_path(node->father);    
    }
    else
    {
        cv::namedWindow( "planner monitor", cv::WINDOW_AUTOSIZE);
        cv::imshow( "planner monitor", m_map_whole_color);
        cv::waitKey(0);
    }
}
 
void AStar::draw_online()
{
    cv::Mat m_map_show = m_map_whole_gray.clone();
 
    for (int i = 0; i < m_open_list.size() - 1; i++)
    {
        cv::circle(m_map_show, cv::Point((int)(m_open_list[i]->x), (int)(m_open_list[i]->y)), 1, cv::Scalar(0, 0, 0), -1);
    }
    cv::circle(m_map_show, cv::Point((int)(m_open_list[0]->x), (int)(m_open_list[0]->y)), 3, cv::Scalar(0, 0, 255), -1);
    cv::Mat m_map_local = m_map_show(cv::Rect(m_open_list[0]->x - 200, m_open_list[0]->y - 200, 
        400, 400));
 
    cv::namedWindow( "planner monitor", cv::WINDOW_AUTOSIZE);
    cv::imshow( "planner monitor", m_map_local);
    cv::waitKey(50);
 
}
 
void AStar::clear_memory()
{
 
}

效果

代码中的图片是我在网上随便搜的一张SLAM建图建出来的2D地图

这是在代码中设置了起点和终点跑出来的效果