用Python实现让微信地球转起来附代码!

Python (217) 2023-05-28 23:35:58

微信地球

手机重启后打开微信的一瞬间,会看到一幅有名的图片。

大概是站在月亮上看地球的效果。

你有没有想过,如果上面那个地球转起来会是怎样?

素材

这里有两个表面素材,一个是地球表面素材,一个是云图素材。

还有一个微信地球的抠图素材。

基本原理

基本的贴图方法在本博前面的文章(《用python实现旋转地球》)中讲过了,这里重点讲双层素材的动态效果。云图是灰度图,白色地方代表云层厚,黑色的地方代表那里云层薄。我们根据颜色设置不同的透明度。

如果云图与地面的选择速度相同,会显得不自然,我们这里让云层旋转速度比地面旋转速度慢一半,产生相对运动的效果。

这样带来的问题是,地球旋转360°后云图只旋转了180°,必须加倍到720°才能实现连续运动。

具体的云层透明度设置,参数需根据实际效果进行调整。

GIF压缩

顺便给大家介绍一个比较好用的压缩GIF的在线工具。

https://www.iloveimg.com/zh-cn/compress-image/compress-gif

直接生成的GIF动图有超过传输限制,无法上传,用此工具压缩后文件体积大幅缩小,但图片效果没有肉眼可以察觉的影响。

完整代码

分步骤的具体逻辑讲解,请看《用python实现旋转地球》,这里贴一下完整代码。

fromPILimportImage,ImageDraw
importmath
importnumpyasnp
importimageio
defcalcSphereXY2XYZ(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
returnv2lon,v1lat
defcalcShpereLatLong2XY(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)
returnv3x2,v3y2
defgetPic(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=[]
foriinrange(w):
forjinrange(h):
r=math.sqrt((i-w/2)**2+(j-h/2)**2)
ifr<circleSize/2:
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]
foriinrange(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)
ifc0>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)
returnimg
if__name__=='__main__':
frames=[]
str1='微信地球_mask.png'
img1=Image.new('RGB',(750,1334))
img2=Image.open(str1)
foriinrange(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知识,请关注Python视频教程!!

THE END

发表回复