A星算法的python实现

课上作业要去找A*算法的代码并解释,看了解释,大概知道了算法原理,找写的代码感觉都不是很清楚,就自己用python写了一下。
讲一下大致思路,我是用图片作为地图,以读入图片的灰度值,用来判断是否是障碍物,起始点与终点也是直接在图片上选取,看起来比较直观。
这里用来类定义了点(Point),地图(Map)和算法主体(DStar)。

# -*- coding = utf-8 -*-
# @Time : 2021/4/1 13:41
# @Software : PyCharm
import cv2

class Point(object):
    def __init__(self,loc,endPoint,g = 0,fatherPoint = None):
        self.loc = loc
        self.G = g
        self.fatherPoint = fatherPoint
        self.endPoint = endPoint

    def H(self):
        d = abs(self.endPoint[0] - self.loc[0]) + abs(self.endPoint[1] - self.loc[1])
        return d

    def F(self):
        f = self.G + self.H()
        return f

    def neighbers(self,step):
        a = []
        # b = point()
        add = [{'偏移量': [-step, 0], '代价': step}, {'偏移量': [-step, -step], '代价': 1.4 * step},
               {'偏移量': [0, -step], '代价': step},{'偏移量': [step, -step], '代价': 1.4 * step},
               {'偏移量': [step, 0], '代价': step},{'偏移量': [step, step], '代价': 1.4 * step},
               {'偏移量': [0, step], '代价': step}, {'偏移量': [-step, step], '代价': 1.4 * step}]
        for item in add:
            loc = [self.loc[0]+item['偏移量'][0],self.loc[1]+item['偏移量'][1]]
            G = self.G + item['代价']
            # 此处各个相邻点的父节点就是self点本身
            b = Point(loc, self.endPoint, G, self)
            a.append(b)
        return a


class Map(object):
    point = []
    def __init__(self,img):
        self.drawMap = cv2.imread(img)
        self.checkMap = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
        self.width = self.checkMap.shape[1]
        self.height = self.checkMap.shape[0]

    def on_EVENT_LBUTTONDOWN(self,event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            self.point.append([x, y])
            cv2.imshow('image', self.checkMap)

    def start_end(self):
        cv2.namedWindow('image')
        cv2.imshow('image', self.checkMap)
        cv2.setMouseCallback('image', self.on_EVENT_LBUTTONDOWN)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        print("起点:",self.point[0],"终点:",self.point[1])
        return self.point

    def is_block(self,point):
        a = point.loc
        # print(a[0],a[1])
        if self.checkMap[a[1],a[0]] == 0:
            return True
        else:
            return False

    def Route(self,point,v):
        a = point.loc
        b = point.fatherPoint.loc
        cv2.line(self.drawMap,tuple(a),tuple(b),(0,255,0),3)
        cv2.imshow('img', self.drawMap)
        cv2.waitKey(v)
        return point.fatherPoint

    def rectangular(self,point,color,step,v):
        img = self.drawMap
        x1 = int(point[0]-step/2)
        y1 = int(point[1]-step/2)
        x2 = int(point[0]+step/2)
        y2 = int(point[1]+step/2)
        cv2.rectangle(img, (x1, y1), (x2, y2), color)
        cv2.imshow('img', img)
        cv2.waitKey(v)
        return


class DStar(object):
    closeList = []
    openList = []
    def __init__(self,startPoint,endPoint,step,map,v):
        self.startPoint = startPoint
        self.endPoint = endPoint
        self.step = step
        self.map = map
        self.v = v

    def __minF(self,point):
        map = self.map
        v = self.v
        step = self.step
        closeList = self.closeList
        openList = self.openList

        # 将父节点以红色表示
        map.rectangular(point.loc,(0,0,255),step,v)

        if point == self.startPoint:
            openList.append(point)

        b = point.neighbers(step)
        for item in b:
            # 检查周围节点是否超过了地图边界
            if item.loc[0] >= map.width or item.loc[1] >= map.height:
                continue

            # 检查点周围画框的点是否超过边界或者是出于障碍上,应该先判断是否超过边界
            # 以tag为标志,以便跳出双重循环
            tag = False
            for i in item.neighbers(step//2):
                if i.loc[0] >= map.width or i.loc[1] >= map.height or map.is_block(i) :
                    tag = True
                    break
            if tag:
                continue

            # 检查周围节点是否已经位于clostList中
            check = []
            for i in closeList:
                check.append(i.loc)
            if item.loc in check:
                continue

            # 判断周围节点是否位于openList中
            tag = False
            for k in openList:
                if item.loc == k.loc :
                    if k.G > item.G:
                        k.fatherPoint = item
                    tag = True
                    break
            if tag:
                continue

            # 若与终点距离足够小,则减少step值,以保证精确度
            if item.H() < 5:
                self.step = 1
            openList.append(item)
            map.rectangular(item.loc, (0, 255, 0), step, v)

        openList.remove(point)
        closeList.append(point)

        a = []
        for item in openList:
            a.append(item.F())
        b = a.index(min(a))
        return openList[b]

    def route(self):
        map = self.map
        a = self.startPoint
        while a.H() != 0:
            a = self.__minF(a)
        p = self.closeList[-1]
        while True:
            p = map.Route(p,self.v)
            if p == self.startPoint:
                break

        cv2.imshow('img', map.drawMap)
        cv2.waitKey(0)

if __name__ == "__main__":

    map = Map("img_2.png")
    a = map.start_end()
    startPoint = a[0]
    endPoint = a[1]
    map.rectangular(startPoint,(0,0,255),3,5)
    map.rectangular(endPoint,(0,0,255),3,5)

    a = Point(startPoint, endPoint)
    b = endPoint

    c = DStar(a,b,3,map,1)
    c.route()

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值