如何用Python把微信這個(gè)地球轉(zhuǎn)動(dòng)?
作者?|?xiaorang
來(lái)源 |?數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)之美
1.微信地球
手機(jī)重啟后打開(kāi)微信的一瞬間,會(huì)看到一幅有名的圖片,上面站著一個(gè)張小龍。

你可曾想過(guò)這樣一個(gè)問(wèn)題,如果上面那個(gè)地球轉(zhuǎn)起來(lái)會(huì)是怎樣?
2.效果圖

效果簡(jiǎn)直不要太酷炫,我只能直呼太牛逼!那么這樣一個(gè)酷炫的操作是怎么做出來(lái)的呢?我們接著往下看。
3.素材準(zhǔn)備
這里共需要準(zhǔn)備三個(gè)素材:1.地球表面素材;2.云圖素材;3.微信地球的摳圖素材。
1)地球表面素材

2)云圖素材

3)微信地球的摳圖素材

4.基本原理
基本的貼圖方法在本博前面的文章《用python實(shí)現(xiàn)旋轉(zhuǎn)地球》中講過(guò)了,具體可以參考下面的鏈接,這里重點(diǎn)講雙層素材的動(dòng)態(tài)效果。云圖是灰度圖,白色地方代表云層厚,黑色的地方代表那里云層薄,我們根據(jù)顏色設(shè)置不同的透明度。
https://blog.csdn.net/xiaorang/article/details/106692489
如果云圖與地面的選擇速度相同,會(huì)顯得不自然,我們這里讓云層旋轉(zhuǎn)速度比地面旋轉(zhuǎn)速度慢一半,產(chǎn)生相對(duì)運(yùn)動(dòng)的效果。
這樣帶來(lái)的問(wèn)題是,地球旋轉(zhuǎn)360°后云圖只旋轉(zhuǎn)了180°,必須加倍到720°才能實(shí)現(xiàn)連續(xù)運(yùn)動(dòng)。
具體的云層透明度設(shè)置,參數(shù)需根據(jù)實(shí)際效果進(jìn)行調(diào)整。
5.GIF壓縮
順便給大家介紹一個(gè)比較好用的壓縮GIF的在線工具,鏈接如下。
https://www.iloveimg.com/zh-cn/compress-image/compress-gif
直接生成的GIF動(dòng)圖有超過(guò)傳輸限制,無(wú)法上傳,用此工具壓縮后文件體積大幅縮小,但圖片效果沒(méi)有肉眼可以察覺(jué)的影響。
6.完整代碼
分步驟的具體邏輯講解,請(qǐng)看《用python實(shí)現(xiàn)旋轉(zhuǎn)地球》這個(gè)文章,鏈接我們?cè)谏厦嬉呀?jīng)展示,這里貼一下完整代碼。
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?r2:
????????????????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)?
???
源碼和素材圖片已經(jīng)上傳至網(wǎng)盤,感興趣的同學(xué)可以下載試試哦!
源碼鏈接:https://pan.baidu.com/s/14SO4hp84fcCtfxFdlZTV9w ?提取碼:0jfa

