微信地球
手机重启后打开微信的一瞬间,会看到一幅有名的图片。
大概是站在月亮上看地球的效果。
你有没有想过,如果上面那个地球转起来会是怎样?
素材
这里有两个表面素材,一个是地球表面素材,一个是云图素材。
还有一个微信地球的抠图素材。
基本原理
基本的贴图方法在本博前面的文章(《用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视频教程!!