小屌丝:鱼哥, 最近在干啥嘞。
小鱼:干活呗, 不然能干啥。
小屌丝:嘿嘿…
小鱼:你这笑的, 怎么 那么 龌(wei)龊(suo)。
小屌丝:没有… 没有…
小鱼:别装了, 无事不登三宝殿的人, 说吧,你有啥事?
小屌丝:果然, 有什么瞒不过鱼哥。
小鱼:那是~ ! 也不看看我是谁~ !
小屌丝:我女神给我发一个动图,我不知道啥意思。
小鱼:啥动图,哪来看看。
小屌丝:就是这个。
小鱼:然后呢,
小屌丝:然后又发了一个图。
小鱼:啥图, 展示下。
小屌丝:鱼哥,你说这是啥意思呢?
小鱼:别慌,待我想一想。
小屌丝:鱼哥,想的怎么样了。
小鱼:别说, 我还真知道了
小屌丝:真的啊, 那快说说, 我的女神想要啥?
小鱼:当然是,旋转的动图了。
小屌丝:可以啊,鱼哥, 没想到,你竟然能get到我女神的想法。
小鱼:… 赶紧制作模型, 赶紧交差,不然赶不上2路公共汽车了。
小屌丝:我女神也没给我期限,你这咋这么着急?
小鱼:… 我的意思,待会 35号(技…师…)该下班了。
小屌丝:…
1、 准备素材
要想让地球转起来, 我们首选要做的准备素材。这里需要准备3个素材,如下:
2、实现原理
很简单,就是利用gif动图来实现的。
具体方法:
这里的难点,有两个,
所以,我们单独分析这两个方法,然后再进行代码整合。
获取经纬度对应的xy坐标
# -*- coding:utf-8 -*-
# @Time : 2023-06-10
# @Author : Carl_DJ
"""
实现原理: 制作一个简单的坐标映射
"""
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
代码示例
# -*- coding:utf-8 -*-
# @Time : 2023-06-10
# @Author : Carl_DJ
'''
实现功能:
使用PIL、numpy等库,让微信登录界面的地球转起来。
'''
from PIL import Image, ImageDraw
import math
import numpy as np
import imageio
#获取三维坐标,这里用到的numpy,为了提升计算的速度
def calcXYZ(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)
# print('z:', max(v1z), min(v1z))
v1lat= np.multiply(v1y, math.pi/2)
v0lon= np.arctan2(v1z, -v1x)
v1lon= np.add(v0lon, longOffset)
v2lon= np.fmod(v1lon, math.pi*2)
return v2lon, v1lat
#获取经纬度对应的xy坐标
def calcLongXY(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('./data/地球日图片.jpg')
imgCloud= Image.open('./data/地球云地图.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<circleSize/2:
pxList.append(i)
pyList.append(j)
nplon, nplat= calcXYZ(pxList, pyList, h/2, a)
nplon2, nplat2= calcXYZ(pxList, pyList, h/2, a/2)
# nplon, nplat= rotSphere(nplon, nplat, )
npx, npy= calcXY(nplon, nplat, width-1, height)
npx2, npy2= calcXY(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=[]
str_path1= './data/微信地图.png'
img1= Image.new('RGB', (750,1300))
img2= Image.open(str_path1)
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)
str_path1= 'Demo.png'%i
img1.save(str_path1)
im = imageio.imread(str_path1)
frames.append(im)
# img.show()
imageio.mimsave('earth.gif', frames, 'GIF', duration=0.20)
运行结果:
小屌丝:鱼哥,运行结果是啥样的呢?
小鱼:嘿嘿,这里留个彩蛋, 你自己运行下代码, 看看呗。
小屌丝:鱼哥,好事做到底啊。 你就直接把图放上来呗。
小鱼:那不行,不能什么都等着我喂到嘴里的。
小屌丝:那我来运行看看。
看到这里,今天的分享就到这里 。
其实我们来回想一下,其实通篇的难点就2个,即:
但是,针对GIF图片的制作, 你可以参照小鱼的这篇博文:
关于 获取坐标经纬度, 你也可以参照小鱼的这篇博文:
所以,看过这几篇,在回来从新看这段代码, 是不是就很简单了呢 。
我是小鱼:
我是小鱼,关注我,带你学习更多更专业更前沿的Python技术。