0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Python的自动追踪算法

新机器视觉 来源:新机器视觉 作者:新机器视觉 2022-10-19 14:17 次阅读

这里涉及拦截导弹的自动跟踪。最近,看到了一个挺有趣的自动跟踪算法,一个Python的简单模拟版本,分享给大家。

自动追踪算法,在我们设计2D射击类游戏时经常会用到,这个听起来很高大上的东西,其实也并不是军事学的专利,在数学上解决的话需要去解微分方程。

这个没有点数学基础是很难算出来的。但是我们有了计算机就不一样了,依靠计算机极快速的运算速度,我们利用微分的思想,加上一点简单的三角学知识,就可以实现它。

好,话不多说,我们来看看它的算法原理,看图:

be54c770-4f67-11ed-a3b6-dac502259ad0.png

由于待会要用pygame演示,他的坐标系是y轴向下,所以这里我们也用y向下的坐标系。

算法总的思想就是根据上图,把时间t分割成足够小的片段(比如1/1000,这个时间片越小越精确),每一个片段分别构造如上三角形,计算出导弹下一个时间片走的方向(即∠a)和走的路程(即vt=|AC|),这时候目标再在第二个时间片移动了位置,这时刚才计算的C点又变成了第二个时间片的初始点,这时再在第二个时间片上在C点和新的目标点构造三角形计算新的vt,然后进入第三个时间片,如此反复即可。

假定导弹和目标的初始状态下坐标分别是(x1,y1),(x,y),构造出直角三角形ABE,这个三角形用来求∠a的正弦和余弦值,因为vt是自己设置的,我们需要计算A到C点x和y坐标分别移动了多少,移动的值就是AD和CD的长度,这两个分别用vt乘cosa和sina即可。

计算sina和cosa,正弦对比斜,余弦邻比斜,斜边可以利用两点距离公式计算出,即:

be7d0da2-4f67-11ed-a3b6-dac502259ad0.png

于是

be9584ea-4f67-11ed-a3b6-dac502259ad0.png

AC的长度就是导弹的速度乘以时间即 |AC|=vt,然后即可计算出AD和CD的长度,于是这一个时间片过去后,导弹应该出现在新的位置C点,他的坐标就是老的点A的x增加AD和y减去CD。

于是,新的C点坐标就是:

bebbfbac-4f67-11ed-a3b6-dac502259ad0.png

只要一直反复循环执行这个操作即可,好吧,为了更形象,把第一个时间片和第二个时间片放在一起看看:

bed5636c-4f67-11ed-a3b6-dac502259ad0.png

第一个是时间片构造出的三角形是ABE,经过一个时间片后,目标从B点走到了D点,导弹此时在C点,于是构造新的三角形CDF,重复刚才的计算过程即可。

图中的角∠b就是导弹需要旋转的角度,现实中只需要每个时间片修正导弹的方向就可以了,具体怎么让导弹改变方向,这就不是我们需要研究的问题了。

好,由于最近在用Python的pygame库制作小游戏玩,接下来我们就用pygame来演示一下这个效果,效果如下图:

bef4b7c6-4f67-11ed-a3b6-dac502259ad0.gif

很简单的代码如下:

importpygame,sys
frommathimport*
pygame.init()
screen=pygame.display.set_mode((800,700),0,32)
missile=pygame.image.load('element/red_pointer.png').convert_alpha()
x1,y1=100,600#导弹的初始发射位置
velocity=800#导弹速度
time=1/1000#每个时间片的长度
clock=pygame.time.Clock()
old_angle=0
whileTrue:
foreventinpygame.event.get():
ifevent.type==pygame.QUIT:
sys.exit()
clock.tick(300)
x,y=pygame.mouse.get_pos()#获取鼠标位置,鼠标就是需要打击的目标
distance=sqrt(pow(x1-x,2)+pow(y1-y,2))#两点距离公式
section=velocity*time#每个时间片需要移动的距离
sina=(y1-y)/distance
cosa=(x-x1)/distance
angle=atan2(y-y1,x-x1)#两点线段的弧度值
x1,y1=(x1+section*cosa,y1-section*sina)
d_angle=degrees(angle)#弧度转角度
screen.blit(missile,(x1-missile.get_width(),y1-missile.get_height()/2))
dis_angle=d_angle-old_angle#dis_angle就是到下一个位置需要改变的角度
old_angle=d_angle#更新初始角度
pygame.display.update()

如果仅把导弹考虑为一个质点的话,那么以上算法就已经足矣,我没有做导弹的旋转,因为一个质点也不分头尾不需要旋转,当然这前提得是你加载的导弹图片很小的时候不旋转看起来也没什么问题。

但是在pygame里面做旋转并不是一件容易的事情(也可能是我无知),好吧我们先把图片替换成一张矩形的,再加入旋转函数看看效果如何。

bfc428a8-4f67-11ed-a3b6-dac502259ad0.png

missiled=pygame.transform.rotate(missile,-(d_angle))
screen.blit(missiled,(x1-missile.get_width(),y1-missile.get_height()/2))

因为图片的坐标点是它的左上角的点,所以如果我们想让图片的坐标固定在箭头尖点,那么把图片实际打印位置x减少图片长度,y减少一半宽度就行。

但是实际运行效果并不好:

bef4b7c6-4f67-11ed-a3b6-dac502259ad0.gif

大致方向相同,但是图片箭头的尖点并没有一直跟随鼠标,这是为什么呢。经过我的研究(就因为这个问题没解决一直没发布),

我发现原来是这个图旋转的机制问题,我们看看旋转后的图片变成什么样了:

c0099c94-4f67-11ed-a3b6-dac502259ad0.png

旋转后的图片变成了蓝色的那个范围,根据旋转角度的不同,所变成的图片大小也不一样,我们看旋转90的情况:

c043b488-4f67-11ed-a3b6-dac502259ad0.pngc05f1c14-4f67-11ed-a3b6-dac502259ad0.png

我们发现,旋转后的图片不仅面积变大了,导弹头的位置也变了。那应该怎么解决这个问题呢?思路是,每一次旋转图片以后,求出旋转图的头位置(图中的绿色箭头点),然后把绿图的打印位置移动一下,下,x,y分别移动两个头的距离,就可以让旋转后的导弹头对准实际我们参与运算的那个导弹头的位置,移动后应该是这样的:

c0923806-4f67-11ed-a3b6-dac502259ad0.png

这样,两个导弹头的点就一致了。接下来我们分析求旋转后的导弹头的算法。根据旋转角度的不同,旋转角在不同象限参数不一样,所以我们分为这四种情况

1,2象限:

c0b08996-4f67-11ed-a3b6-dac502259ad0.png

3,4象限,它的旋转只有正负0—180,所以3,4象限就是负角。

c10d8a60-4f67-11ed-a3b6-dac502259ad0.png

显示图片的时候我们将他移动。

screen.blit(missiled,(x1-width+(x1-C[0]),y1-height/2+(y1-C[1])))

这里的(x1-width,y1-height/2)其实才是上图中的(x1,y1)。

所以最后我们加入相关算法代码,效果就比较完美了。

c15e32f8-4f67-11ed-a3b6-dac502259ad0.gif

大功告成,最后附上全部的算法代码:

importpygame,sys
frommathimport*
pygame.init()
font1=pygame.font.SysFont('microsoftyaheimicrosoftyaheiui',23)
textc=font1.render('*',True,(250,0,0))
screen=pygame.display.set_mode((800,700),0,32)
missile=pygame.image.load('element/rect1.png').convert_alpha()
height=missile.get_height()
width=missile.get_width()
pygame.mouse.set_visible(0)
x1,y1=100,600#导弹的初始发射位置
velocity=800#导弹速度
time=1/1000#每个时间片的长度
clock=pygame.time.Clock()
A=()
B=()
C=()
whileTrue:
foreventinpygame.event.get():
ifevent.type==pygame.QUIT:
sys.exit()
clock.tick(300)
x,y=pygame.mouse.get_pos()#获取鼠标位置,鼠标就是需要打击的目标
distance=sqrt(pow(x1-x,2)+pow(y1-y,2))#两点距离公式
section=velocity*time#每个时间片需要移动的距离
sina=(y1-y)/distance
cosa=(x-x1)/distance
angle=atan2(y-y1,x-x1)#两点间线段的弧度值
fangle=degrees(angle)#弧度转角度
x1,y1=(x1+section*cosa,y1-section*sina)
missiled=pygame.transform.rotate(missile,-(fangle))
if0<=-fangle<=90:
        A=(width*cosa+x1-width,y1-height/2)
        B=(A[0]+height*sina,A[1]+height*cosa)

    if 90<-fangle<=180:
        A = (x1 - width, y1 - height/2+height*(-cosa))
        B = (x1 - width+height*sina, y1 - height/2)

    if -90<=-fangle<0:
        A = (x1 - width+missiled.get_width(), y1 - height/2+missiled.get_height()-height*cosa)
        B = (A[0]+height*sina, y1 - height/2+missiled.get_height())

    if -180<-fangle<-90:
        A = (x1-width-height*sina, y1 - height/2+missiled.get_height())
        B = (x1 - width,A[1]+height*cosa )

    C = ((A[0] + B[0]) / 2, (A[1] + B[1]) / 2)

    screen.fill((0,0,0))
    screen.blit(missiled, (x1-width+(x1-C[0]),y1-height/2+(y1-C[1])))
    screen.blit(textc, (x,y)) #鼠标用一个红色*代替
    pygame.display.update()

最后

这是一个简单的,用 Python 实现的自动跟踪算法,真正的导弹拦截跟踪算法要复杂很多。

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4741

    浏览量

    68325
  • 自动跟踪
    +关注

    关注

    0

    文章

    21

    浏览量

    9342
  • python
    +关注

    关注

    55

    文章

    4778

    浏览量

    84439

原文标题:太强了,手撸一款导弹跟踪算法(Python版)

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    DRV2605:自动谐振追踪要点剖析

    DRV260x系列器件使用一种名为自动谐振追踪的特殊LRA控制算法自动谐振追踪使用LRA的反电动势 (back-EMF) 来检测和
    发表于 10-29 11:36 9073次阅读
    DRV2605:<b class='flag-5'>自动</b>谐振<b class='flag-5'>追踪</b>要点剖析

    盘点史上最全的Python算法

    本文是一些机器人算法(特别是自动导航算法)的Python代码合集。其主要特点有以下三点:选择了在实践中广泛应用的算法;依赖最少;容易阅读,容
    的头像 发表于 02-21 10:04 6008次阅读

    Python的Apriori算法和FP-Growth算法是什么

    [源码和文档分享]基于Python实现的Apriori算法和FP-Growth算法的频繁项集挖掘的研究与实现
    发表于 06-04 12:49

    追踪算法自行车模型

    追踪算法自行车模型自行车模型是对汽车运动描述的一种简化方法,其基于几个假设:忽略车辆垂直方向上的运动假设前面的两个轮胎具有一致的角度和转速,后面也如此,这样车辆就可以简化成自行车结构车辆运动
    发表于 08-17 08:58

    什么是纯追踪算法

    什么是纯追踪算法
    发表于 11-22 06:08

    什么是基追踪算法?基于改进基追踪方法的信号去噪

    追踪(basis pursuit)算法是一种用来求解未知参量L1范数最小化的等式约束问题的算法。字典的构造 对于观测到的离散信号s∈H,H为Hilbert空间,给定H中的字典φ={φγ,γ∈Γ},其中Γ为指标集,φγ为H中的基
    发表于 12-01 16:04 1.1w次阅读
    什么是基<b class='flag-5'>追踪</b><b class='flag-5'>算法</b>?基于改进基<b class='flag-5'>追踪</b>方法的信号去噪

    蚁群算法python编程实现

    本文主要介绍了Python编程实现蚁群算法详解,涉及蚂蚁算法的简介,主要原理及公式,以及Python中的实现代码,具有一定参考价值。
    发表于 02-02 10:36 7440次阅读
    蚁群<b class='flag-5'>算法</b><b class='flag-5'>python</b>编程实现

    光线追踪算法汇总

    在基本光线追踪算法中,只追踪有限数目的光线。
    的头像 发表于 05-11 15:58 1.7w次阅读
    光线<b class='flag-5'>追踪</b><b class='flag-5'>算法</b>汇总

    组合29个简单Python代码块,自动发现新算法

    本文提出了一种基于演化算法的搜索策略,将其AAD中实现。AAD可以基于Python的子集作为语法结构,组合成复杂度相对较高的程序(循环,嵌套块,嵌套函数调用等),并生成可执行的Python代码。在本文中使用AAD来发现数组/向量
    的头像 发表于 04-19 13:47 3483次阅读

    Python模拟导弹自动追踪的代码实例

    自动追踪算法,在我们制作射击类游戏时经常会用到。这个听起来很高大上的东西,其实并不是军事学的专利,从数学上来说就是解微分方程,这个没有点数学基础是很难算出来的。但是我们有了计算机就不一样了,依靠
    的头像 发表于 06-13 16:35 1405次阅读
    <b class='flag-5'>Python</b>模拟导弹<b class='flag-5'>自动</b><b class='flag-5'>追踪</b>的代码实例

    Python实现所有算法-基本牛顿法

    Python实现所有算法-二分法 Python实现所有算法-力系统是否静态平衡 Python实现所有算法
    的头像 发表于 07-13 10:40 1610次阅读

    Python实现自动驾驶

    今天来一个好玩一点的,汽车已经能够自动驾驶了,Python怎么能没有呢?这不,必须安排上。 一、安装环境 gym是用于开发和比较强化学习算法的工具包,在python中安装gym库和其中
    发表于 06-06 10:43 1次下载
    <b class='flag-5'>Python</b>实现<b class='flag-5'>自动</b>驾驶

    [源代码]Python算法详解

    [源代码]Python算法详解[源代码]Python算法详解
    发表于 06-06 17:50 0次下载

    如何使用Python进行图像识别的自动学习自动训练?

    如何使用Python进行图像识别的自动学习自动训练? 使用Python进行图像识别的自动学习和自动
    的头像 发表于 01-12 16:06 535次阅读

    Python建模算法与应用

    上成为理想的脚本语言,特别适用于快速的应用程序开发。本文将详细介绍Python在建模算法中的应用,包括常见的建模算法Python在建模中的优势、常用库以及实际案例。
    的头像 发表于 07-24 10:41 453次阅读