Python3, 19行代码,让微信登录页面地球转起来,涨见识了。

19行代码动态展示微信地图

  • 1、引言
  • 2、代码实战
    • 2.1 思路
    • 2.2 示例
      • 2.2.1 经纬度
      • 2.2.2 制作gif
  • 3、总结

1、引言

小屌丝:鱼哥, 最近在干啥嘞。
小鱼:干活呗, 不然能干啥。
小屌丝:嘿嘿…
小鱼:你这笑的, 怎么 那么 龌(wei)龊(suo)。
小屌丝:没有… 没有…
小鱼:别装了, 无事不登三宝殿的人, 说吧,你有啥事?
小屌丝:果然, 有什么瞒不过鱼哥。
小鱼:那是~ ! 也不看看我是谁~ !
小屌丝:我女神给我发一个动图,我不知道啥意思。
小鱼:啥动图,哪来看看。
小屌丝:就是这个。
Python3, 19行代码,让微信登录页面地球转起来,涨见识了。_第1张图片

小鱼:然后呢,
小屌丝:然后又发了一个图。
小鱼:啥图, 展示下。
Python3, 19行代码,让微信登录页面地球转起来,涨见识了。_第2张图片

小屌丝:鱼哥,你说这是啥意思呢?
小鱼:别慌,待我想一想。
Python3, 19行代码,让微信登录页面地球转起来,涨见识了。_第3张图片
小屌丝:鱼哥,想的怎么样了。
小鱼:别说, 我还真知道了
小屌丝:真的啊, 那快说说, 我的女神想要啥?
小鱼:当然是,旋转的动图了。
Python3, 19行代码,让微信登录页面地球转起来,涨见识了。_第4张图片

小屌丝:可以啊,鱼哥, 没想到,你竟然能get到我女神的想法。
小鱼:… 赶紧制作模型, 赶紧交差,不然赶不上2路公共汽车了。
小屌丝:我女神也没给我期限,你这咋这么着急?
小鱼:… 我的意思,待会 35号(技…师…)该下班了。
小屌丝:…
Python3, 19行代码,让微信登录页面地球转起来,涨见识了。_第5张图片

2、代码实战

2.1 思路

1、 准备素材

要想让地球转起来, 我们首选要做的准备素材。这里需要准备3个素材,如下:

  • 地球表面;
  • 云图;
  • 微信地球抠图;

2、实现原理
很简单,就是利用gif动图来实现的。

具体方法:

  • 选择图片上所有的点;
  • 计算每一个点对应的经纬度(经纬度是重点);
  • 获取经纬度的xy坐标;
  • 像素写入到图片中;
  • 制作gif动图,实现地球不停旋转。

2.2 示例

这里的难点,有两个,

  • 经纬度
  • gif制作

所以,我们单独分析这两个方法,然后再进行代码整合。

2.2.1 经纬度

获取经纬度对应的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

2.2.2 制作gif

代码示例

# -*- 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) 

运行结果

小屌丝:鱼哥,运行结果是啥样的呢?
小鱼:嘿嘿,这里留个彩蛋, 你自己运行下代码, 看看呗。

小屌丝:鱼哥,好事做到底啊。 你就直接把图放上来呗。
小鱼:那不行,不能什么都等着我喂到嘴里的。
小屌丝:那我来运行看看。

3、总结

看到这里,今天的分享就到这里 。
其实我们来回想一下,其实通篇的难点就2个,即:

  • 1、如何获取经纬度的xy坐标,并且把像素写入到图片中;
  • 2、GFI图片制作;

但是,针对GIF图片的制作, 你可以参照小鱼的这篇博文:

  • Python3,5行代码,制作Gif动图,太简单了。

关于 获取坐标经纬度, 你也可以参照小鱼的这篇博文:

  • Python3,19行代码,我把她的照片写入到Excel中,2022年伊始,她终于被我感动了。
  • Python3,为了给女神暗送秋波,我默默的写了一个图片字符画生成器,真香。

所以,看过这几篇,在回来从新看这段代码, 是不是就很简单了呢 。

我是小鱼

  • CSDN 博客专家
  • 阿里云 专家博主
  • 51CTO博客专家
  • 51认证讲师等
  • 认证金牌面试官
  • 职场面试及培训规划师
  • 国内多个主流技术社区的认证专家博主
  • 多款主流产品(阿里云等)测评一、二等奖获得者

我是小鱼,关注我,带你学习更多更专业更前沿的Python技术。

你可能感兴趣的:(python,numpy)