作者 | xiaorang
责编?|?Aholiab
头图 | CSDN 下载自视觉中国
出品 | CSDN(ID:CSDNnews)
手机重启后打开微信的一瞬间,会看到一幅有名的图片,上面站着一个“张小龙”。
你可曾想过这样一个问题,如果上面那个地球转起来会是怎样?就像下面这样:
效果简直不要太酷炫,那么这样一个酷炫的操作是怎么做出来的呢?我们接着往下看。
这里共需要准备三样素材:
地球表面素材
云图素材
微信地球的抠图素材
地球表面素材如下所示:
云图素材如下所示:
微信地球抠图素材如下所示:
这里重点讲双层素材的动态效果。云图是灰度图,白色地方代表云层厚,黑色的地方代表那里云层薄,我们根据颜色设置不同的透明度。
如果云图与地面的选择速度相同,会显得不自然,我们这里让云层旋转速度比地面旋转速度慢一半,产生相对运动的效果。
这样带来的问题是,地球旋转360°后云图只旋转了180°,必须加倍到720°才能实现连续运动。
具体的云层透明度设置,参数需根据实际效果进行调整。
接下来是GIF压缩,顺便给大家介绍一个比较好用的GIF压缩工具iloveimg。用这个工具可以直接生成GIF动图,并且不会超过传输限制。用此工具压缩后文件体积大幅缩小,但图片效果没有肉眼可以察觉的影响。
那么,最关键的一步来了,我们该如何用Python实现旋转地球的效果呢?完整代码如下所示:
from?PIL?import?Image,?ImageDraw
import?math
import?numpy?as?np
import?imageio
def?calcSphereXY2XYZ(px,?py,?maxHeight,?longOffset):
v0x=?np.array(px)
v0y=?np.array(py)
v03=?np.subtract(v0x,?maxHeight)
v04=?np.subtract(v0y,?maxHeight)
v1x=?np.true_divide(v03,?maxHeight)
v1y=?np.true_divide(v04,?maxHeight)
#?print(max(v1x),?min(v1x))
v07=?np.power(v1x,2)
v08=?np.power(v1y,2)
v09=?np.add(v07,v08)
v0a=?np.subtract(1,v09)
v1z=?np.power(v0a,1/2)??????????????????????????????????#?z
#?print('z:',?max(v1z),?min(v1z))
v1lat=?np.multiply(v1y,?math.pi/2)??????????????????????#?lat
v0lon=?np.arctan2(v1z,?-v1x)
v1lon=?np.add(v0lon,?longOffset)???????????????????????#?long
v2lon=?np.fmod(v1lon,?math.pi*2)???????????????????????#?long
return?v2lon,?v1lat
def?calcShpereLatLong2XY(vlon,?vlat,?width,?height):
v3x0=np.multiply(vlon,?width/2/math.pi)
v3y0=np.multiply(vlat,?height/math.pi)
v3y1=np.add(v3y0,?height/2)
v3x2=v3x0.astype(np.integer)
v3y2=v3y1.astype(np.integer)
return?v3x2,?v3y2
def?getPic(a):
#?imgBack=?Image.open('地球3.jpg')
imgBack=?Image.open('世界地球日地图_8K_2.jpg')
imgCloud=?Image.open('世界地球云地图_8K.jpg')
width=?imgBack.size[0]
height=?imgBack.size[1]
imgBack=?imgBack.convert('RGBA')
arrayBack=?np.array(imgBack)
arrayCloud=?np.array(imgCloud)
circleSize=?508
img2=?Image.new('RGBA',?(circleSize,circleSize))
img=?Image.new('RGBA',?(circleSize,circleSize),?'black')
w=?img.size[0]
h=?img.size[1]
pxList=[]
pyList=[]
for?i?in?range(w):
for?j?in?range(h):
r=?math.sqrt((i-w/2)**2+(j-h/2)**2)
if?r
pxList.append(i)
pyList.append(j)
nplon,?nplat=?calcSphereXY2XYZ(pxList,?pyList,?h/2,?a)
nplon2,?nplat2=?calcSphereXY2XYZ(pxList,?pyList,?h/2,?a/2)
#?nplon,?nplat=?rotSphere(nplon,?nplat,?)
npx,?npy=?calcShpereLatLong2XY(nplon,?nplat,?width-1,?height)
npx2,?npy2=?calcShpereLatLong2XY(nplon2,?nplat2,?width-1,?height)
color=?arrayBack[npy,?npx]
color2=?arrayCloud[npy2,?npx2]
for?i?in?range(len(pxList)):
x=?pxList[i]
y=?pyList[i]
cc=color[i]
#?print(cc)
cc=?tuple(cc)
img.putpixel((x,y),?cc)
c2=?color2[i]
c0=?int(c2[0]*1.6)
if?c0>255:
c0=255
c_alpha=?int(c2[0]*0.9)
c2=?(c0,c0,c0,c_alpha)
img2.putpixel((x,y),?c2)
r,g,b,a=?img2.split()
img.paste(img2,?(0,0),?mask=a)
return?img
if?__name__=='__main__':
frames=[]
str1=?'微信地球_mask.png'
img1=?Image.new('RGB',?(750,1334))
img2=?Image.open(str1)
for?i?in?range(0,?720,?12):
a=?-i*math.pi/?180
img=?getPic(a)
img1.paste(img,(122,424))
r,g,b,alpha=img2.split()
img1.paste(img2,?(0,0),?mask=alpha)
str1=?'temp%03d.png'%i
print(str1)
img1.save(str1)
im?=?imageio.imread(str1)
frames.append(im)
#?img.show()
imageio.mimsave('earth.gif',?frames,?'GIF',?duration=0.20)
对Python感兴趣的同学,可以将上面代码down下来慢慢研究。通过对小项目的实现可以快速提升代码的实操能力。
你学会了吗?如有疑问欢迎在评论区留言。
更多精彩推荐
时隔 15 年,苹果的自研 ARM 芯片为何能取代 Intel 处理器?
从微信「拍一拍」,我想到了那些神奇的一行代码功能
AI 又进阶!除了鉴别 PS 图片,还能一键卸妆!
无代码开发到底是不是伪需求?
程序员端午炫富指南~
Spring 从入门到入土——AOP 就这么简单!| 原力计划
硬核!国外开发者用 25 美元做了个区块链警佩相机!
你点的每个“在看”,我都认真当成了喜欢
领取专属 10元无门槛券
私享最新 技术干货