0
点赞
收藏
分享

微信扫一扫

继承火的意志,结合关键点检测玩个火吧~_副本

转载自AI Studio 项目链接https://aistudio.baidu.com/aistudio/projectdetail/3537977

大哥没有输!继承火的意志~

大哥怎么会输呢,明明是猗窝座耍赖皮,猗窝座不许走!

我正在追杀的路上,现在还差几个fork我就能追上他给大哥报仇了,我没听说过什么项目季度奖励,真的~

这个项目简单首先讲述如何绘制像素风的火,然后结合了一下关键点检测,在我们指定的地方放一把火吧,咳咳~

粒子特效(Particle Effect)

粒子特效被广泛的应用于游戏中,特别是一般的元素(风水火等),以及技能的效果(刀光剑影,魔法奥术)~
所以这个项目,我们也使用粒子特效的方法来绘制火。最简单的就是使用Pygame来绘制这类图像。(其实,我们完全只使用opencv来做,但是pygame实现起来更简单一些。)
说到粒子特效,一般的常见的三个概念就是粒子出生粒子运动以及粒子死亡,而更常用的是我们一般是将多个粒子放在一起使用以展示某种效果,单个粒子的表现力还是不足的。
一般我们会有一个发射器emitter,所有的粒子都是由发射器来生成。
生成之后我们在每一帧绘制粒子的运动,一般来说当粒子运动到一定的时间或地点的时候,就结束了他的使命,迎来了粒子的死亡。

我们先来看粒子类的编写

这里我们定义了x,y粒子的位置,life粒子可以存活多少秒,r粒子的半径,以及几个例子运动的角度值

class Particle:
    def __init__(self, x, y):
        self.x, self.y = x, y
        particleSize = 10#2.9
        self.maxlife = randint(13 + int(particleSize*5), 27 + int(particleSize*10))
        self.life = self.maxlife
        self.dir = choice((-2, -1, 1, 2))
        self.sin = randint(-10, 10)/7
        self.sinr = randint(5, 10)
        self.r = randint(4,8)

        self.ox = randint(-1, 1)
        self.oy = randint(-1, 1)

我们把粒子的生成、运动和死亡统一由发射器emitter来管理,我们先看粒子的生成

发射器类我们会维护一个列表self.particles来管理所有粒子,粒子的出生即不断的像self.particles中append新的粒子实例

def add_particles(self, x, y):
    if self.init:
        dist = sqrt((x-self.lx)**2+(y-self.ly)**2)
        a = atan2(y-self.ly, x-self.lx)
        for d in range(0, int(dist), 10):
            _x = x+cos(a)*d
            _y = y+sin(a)*d
            for _ in range(round(self.density)):
                self.particles.append(Particle(_x//self.res, _y//self.res))
        else:
            for _ in range(round(self.density)):
                self.particles.append(Particle(x//self.res, y//self.res))
        self.lx = x
        self.ly = y
    else:
        self.lx = x
        self.ly = y
        self.init = True

粒子的运动

粒子的运动及是在新的一帧中计算粒子的位置、颜色和大小
在我们这个项目中,粒子的位置会相对于它的出生点一点一点上浮(火都是往上烧的)
而颜色方面,这个项目定义了一个调色板,预置了六种颜色,对应着火焰燃烧的程度,越接近火源的粒子,它的颜色更黄,然后到红,最后到黑
在大小方面,粒子越远离火源,它的size会越大
我们也在这里判断了粒子是否应该死亡,如果粒子已死我们将其置入维护的self.dead列表,在下一次计算运动前,删除所有的死亡粒子

def emit(self, j):
    if self.particles:
        self.delete_particles()
        for p in self.particles:
            p.life -= 1
            if p.life == 0:
                self.dead.append(p)
                continue

            i = int((p.life/p.maxlife)*6)
            p.y -= self.rise
            p.x += ((p.sin * sin( j / (p.sinr)))/2)*self.spread + self.wind

            if not randint(0, 5):
                p.r += 0.88

            x, y = p.x, p.y

            x += p.ox * (5 - i)
            y += p.oy * (5 - i)

            alpha = 255
            if p.life < p.maxlife/4:
                alpha = int((p.life/p.maxlife) * 255)
            
            pygame.draw.circle(self.bsurf, palette[i] + (alpha,), (x, y), p.r, 0)

            if i == 0:
                pygame.draw.circle(self.bsurf, (0, 0, 0, 0), (x+randint(-1, 1), y-4), p.r*(((p.maxlife-p.life)/p.maxlife)/0.88), 0)
            else:
                pygame.draw.circle(self.bsurf, palette[i-1] + (alpha,), (x+randint(-1, 1), y-3), p.r/1.5, 0)

粒子的死亡

没啥说的哈哈,直接把dead列表中的粒子丢掉就好

def delete_particles(self):
        for p in self.dead:
            self.particles.remove(p)
        self.dead.clear()

结合我们PaddleDetection中关键点检测模型

这里把关键点检测封装到一个线程中,这里使用的是PaddleDetection中的hrnet
其实在这里随便替换成其他的模型,譬如我还提供了一个使用手部关键点模型的文件,那个就直接使用的PaddleHub的模型,使用起来非常的简单!

class MyThread(Thread):
    def __init__(self, video_file = "mykeypointdetector/mine.mp4", debug=True):
        global shape
        super(MyThread, self).__init__()  
        self.md = MyDetector("mykeypointdetector/output_inference/hrnet_w32_384x288/", True)
        self.video_file = video_file
        self.debug = debug
        self.capture = cv2.VideoCapture(self.video_file)
        self.h = self.capture.get(4)
        self.w = self.capture.get(3)
        shape = [self.h, self.w]

    def run(self):
        global results
        global lock
        global rframe
        while (1):
            ret, frame = self.capture.read()
            if not ret:
                break
            frame = cv2.flip(frame, 1)
            tresults = self.md.detector.predict(frame)
            if tresults['keypoint'][0][0][10][2] > 0.5 and tresults['keypoint'][0][0][8][2] > 0.5:
                lock.acquire()
                results = tresults
                rframe = frame.copy()
                lock.release()
            else:
                lock.acquire()
                results = tresults
                rframe = frame.copy()
                lock.release()
            '''watch image'''
            if self.debug:
                if tresults is not None:
                    for key in tresults['keypoint'][0][0]:
                        cv2.circle(frame,(int(key[0]), int(key[1])), 5, (0,0,255), -1)
                cv2.imshow("Debug", frame)
cle(frame,(int(key[0]), int(key[1])), 5, (0,0,255), -1)
                cv2.imshow("Debug", frame)
                cv2.waitKey(1)

由于aistudio无法直接交互,所以下载到本地来玩耍吧~

本地运行直接python interaction.py就可以啦

然后尝试按上下左右四个按键,看看有啥效果~

总结:

这个项目主要介绍常用于游戏中的例子特效,以及如何用python来实现简单的火焰特效。
后面与关键点结合的部分,其实可以换成其他的关键点检测模型,我之所以使用项目中的这个完全是因为顺手,咳咳。
其实在PaddleHub中有专业的脸部的关键点检测模型,那个使用起来应该会更加的顺手,而且那个模型运行的非常快,完全不需要像我的项目中使用多线程的方式来书写。
当然,我们生成粒子的地方,当然可以不止是眼睛,可以是身体的任何部位,甚至,是我们手里的剑!但如何让剑染上火焰,这个可能需要别的方法,譬如PaddleSeg?大家可以尝试一下~
之后也会给大家带来其他的粒子特效的项目,一起来玩吧~
如果你喜欢这个项目,还请点一点爱心、fork下次再见

项目火焰粒子特效参考:pygame-vfx

个人简介

我在AI Studio上获得至尊等级,点亮10个徽章,来互关呀!!!

https://aistudio.baidu.com/aistudio/personalcenter/thirdview/311006

B站ID: 玖尾妖熊

其他趣味项目:

Padoodle: 使用人体关键点检测让涂鸦小人动起来

使用关键点检测和分类模型改造体感愤怒的小鸟

利用PaddleHub制作"王大陆"滤镜

利用Paddlehub制作端午节体感小游戏

熊猫头表情生成器[Wechaty+Paddlehub]

如何变身超级赛亚人(一)–帅气的发型

【AI创造营】是极客就坚持一百秒?

在Aistudio,每个人都可以是影流之主[飞桨PaddleSeg]

愣着干嘛?快来使用DQN划船啊

利用PaddleSeg偷天换日~

举报

相关推荐

聊聊火出圈的ChatGPT

爆火出圈的chatGPT

0 条评论