转载自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: 玖尾妖熊