首页 > 编程语言 >python由tif影像绘制png图片并制作动图

python由tif影像绘制png图片并制作动图

时间:2024-08-10 23:27:05浏览次数:11  
标签:plt 动图 img python GIF import path tif os

笔者最近需要下载一个区域的长时间序列影像,然后将其制作成动图展示其动态变化过程。这其中涉及到两个问题,一是将tif数据绘制成PNG或jpg等格式图片,二是由图片绘制动图GIF。

一、由TIF绘制PNG

 这里需要用到matplotlib和GDAL两个库来将tif格式图像绘制为PNG图片,如果没有相关包,则需要提前pip安装。

1.1 导入相关库

from osgeo import gdal
import numpy as np
import os
#os.environ['PROJ_LIB'] = r'E:\ProgramData\Anaconda3\envs\qt39\Lib\site-packages\pyproj\proj_dir\share\proj'
# os.environ['GDAL_DATA'] = r'E:\ProgramData\Anaconda3\envs\qt39\Library\share'
import random
import matplotlib.pyplot as plt
import numpy as np
import imageio

1.2 确定文件读取和输出路径

tifDir = './tifs'
outputDir = './imgs'
if not os.path.exists(outputDir):
    os.makedirs(outputDir)
 
tifs = [i for i in os.listdir(tifDir) if i.endswith(".tif")]
 
print("有 %s 个tif文件" % len(tifs))

1.3 绘制图像

tif = tifs[0]
year = tif.split('_')[2].split('.')[0]
print("正在处理第 %s 年" % year)
path = os.path.join(tifDir,tif)
ds = gdal.Open(path)

def scaleCCC(x):
    return((x - np.nanpercentile(x, 2))/(np.nanpercentile(x, 98) - np.nanpercentile(x,2)))
nir = ds.GetRasterBand(1).ReadAsArray()
r = ds.GetRasterBand(2).ReadAsArray()
g = ds.GetRasterBand(3).ReadAsArray()

ds = None

nir = scaleCCC(nir)
r = scaleCCC(r)
g = scaleCCC(g)

rgb = np.dstack((nir,r,g))
plt.figure()
plt.imshow(rgb)
plt.xticks([])
plt.yticks([])
plt.text(rgb.shape[1]-4, 15, year, fontsize=15, color='white', 
                 verticalalignment='bottom', horizontalalignment='right', 
                 bbox=dict(facecolor='black', alpha=0.5))
plt.tight_layout()

plt.savefig(os.path.join(outputDir, year + '.png'),dpi=300,bbox_inches='tight', pad_inches=0.05)
# plt.show()

这里面是读取了影像的三个波段,分别映射为RGB三个通道,使用np.dstack合成,用线性拉伸的方法增强图像展示效果。

二、由PNG图片绘制GIF动图

2.1 先将PNG图片按照时间顺序排列好

笔者发现,用os.lisdir批量读取文件夹路径后,发现其并不是按照 年份数值大小从小到大读取的,顺序是乱的(其实是根据文件名ASCII码大小从左到右比较后的顺序读取)。因而需要通过某种方式使其读取文件的顺序是我们想要的,即按照文件名中的年份大小一次读取。

imgDir = './imgs'
imgs = [i for i in os.listdir(imgDir) if i.endswith(".png")]

#先定义一个排序的空列表
sort_num_list = []
for img in imgs:
    sort_num_list.append(int(img.split('.')[0])) #去掉前面的字符串和下划线以及后缀,只留下数字并转换为整数方便后面排序
    sort_num_list.sort() #然后再重新排序
    
#print(sort_num_list)
#接着再重新排序读取文件
sorted_file = []
for sort_num in sort_num_list:
    for img in imgs:
        if str(sort_num) == img.split('.')[0]:
            sorted_file.append(img)
            
print(sorted_file)
pathlist = []
for file in sorted_file:
    pathlist.append(os.path.join(imgDir,file))
print(pathlist)

 2.2 绘制GIF

import imageio
 
def imgs2gif(imgPaths, saveName, duration=None, loop=0, fps=None):
    """
    生成动态图片 格式为 gif
    :param imgPaths: 一系列图片路径
    :param saveName: 保存gif的名字
    :param duration: gif每帧间隔,单位 秒
    :param fps: 帧率
    :param loop: 播放次数(在不同的播放器上有所区别), 0代表循环播放
    :return:
    """
    if fps:
        duration = 1 / fps
    images = [imageio.imread(str(img_path)) for img_path in imgPaths]
    imageio.mimsave(saveName, images, "gif", duration=duration, loop=loop, fps = 1/duration)
 
 
 
p_lis = []
for n, p in enumerate(pathlist):
    # if n % 5 == 0:
    p_lis.append(p)
 
imgs2gif(p_lis, "spatiotemporal_change_yh.gif", duration=1, loop = 0)

2.3 压缩动图

如果遇到动图文件过大,则可能需要对其进行压缩,一般是降低每一帧图片的大小。


import imageio
from PIL import Image
import io

def compress_gif(input_path, output_path, quality=30):
    """
    压缩GIF动图
    :param input_path: 输入GIF文件的路径
    :param output_path: 输出压缩后GIF文件的路径
    :param quality: 压缩质量,范围从1到95,数值越小压缩率越高
    """
    # 使用get_reader逐帧读取GIF
    reader = imageio.get_reader(input_path)

    # 准备输出文件
    output_file = io.BytesIO()

    # 保存每一帧,同时指定压缩质量
    optimize = True if quality < 90 else False
    save_kwargs = {
        'format': 'GIF',
        'optimize': optimize,
        'quality': quality,
        'loop': 0  # 设置为0表示无限循环
    }
    
    # 转换每一帧为Pillow Image对象并保存
    frames = []
    for frame in reader:
        img = Image.fromarray(frame)
        frames.append(img)

    frames[0].save(output_file, save_all=True, append_images=frames[1:], **save_kwargs)

    # 将压缩后的GIF写入文件
    with open(output_path, 'wb') as f:
        f.write(output_file.getvalue())

# 示例使用
compress_gif('spatiotemporal_change_yh.gif', 'spatiotemporal_change_yh1.gif', quality=50)

标签:plt,动图,img,python,GIF,import,path,tif,os
From: https://blog.csdn.net/Ailovelearning/article/details/141097806

相关文章

  • 多种优化算法优化LSTM——【包括:粒子群、蝙蝠、正余旋、多元宇宙、正余弦、JAYA、哈里
     ......
  • python 提取日志错误请求批量重新请求
    因为有服务器线上偶发异常,所以需要获取Nginx访问日志重新请求补全数据,这时会借助python获取错误请求的URL,然后重新请求。具体如下:importtimeimportrequestsfromurllib.parseimporturljoin#定义一个集合用于存储已处理的URL,避免重复处理processed_urls=set()with......
  • 107. 项目57:简易节日倒计时——《跟老吕学Python·新手》
    107.项目57:简易节日倒计时107.1目标开发一个简易节日倒计时程序,用户可以选择一个节日,程序将计算并显示距离该节日的天数。107.2功能用户选择一个节日。程序计算从当前日期到节日的天数。程序显示倒计时结果。107.3设计用户选择节日:用户从预设的节日列表中选择一个......
  • python-flask计算机毕业设计新冠肺炎疫情人员统计及打卡系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景自2019年底新冠肺炎疫情爆发以来,全球公共卫生体系面临了前所未有的挑战。疫情的快速传播要求各国政府及社区采取迅速且有效的防控措施,以遏......
  • python-flask计算机毕业设计胜者台球室业务信息管理系统设计与实现(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着休闲娱乐产业的蓬勃发展,台球运动作为一种集竞技性、娱乐性和社交性于一体的体育活动,受到了广大消费者的喜爱。胜者台球室作为该领域的......
  • python-flask计算机毕业设计校园生活圈综合服务系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和高等教育改革的深入,校园生活日益丰富多元,学生对便捷、高效、个性化的校园服务需求日益增长。然而,传统的校园服务......
  • yolov5 onnx部署模型代码,python版本
    `importosimportcv2importnumpyasnpimportonnxruntimeimporttimefromtqdmimporttqdmfrommatplotlibimportpyplotaspltimportmathCLASSES=['jump_cap2','jump_cap4']classYOLOV5():definit(self,onnxpath):self.onnx_se......
  • Python中yaml模块的使用教程
    一、yaml文件介绍yaml是一个专门用来写配置文件的语言。1.yaml文件规则区分大小写;使用缩进表示层级关系;使用空格键缩进,而非Tab键缩进缩进的空格数目不固定,只需要相同层级的元素左侧对齐;文件中的字符串不需要使用引号标注,但若字符串包含有特殊字符则需用引号标注;注释标识......
  • python装饰器的集中使用姿势
    在Python中,装饰器是一种十分强大并且好用的语法,一些重复的代码使用装饰器语法的话能够使代码更容易理解及阅读。因此在这里简单总结了一下Python中装饰器的几种用法以及需要注意的事情。一、在装饰器中获取被装饰函数的参数假设我们在开发web的时候,需要做反爬。要判断接口的访......
  • Python类中__del__()、__call__()、__repr__()、__new__()、__hash__()方法
    1.__del__()销毁魔术方法触发时机:当一个对象在内存中被销毁的时候自动执行参数:至少有一个self,接收对象返回值:无作用:在对象销毁的时候做一些操作注意:程序自动调用此方法,不需要我们手动调用。classCat:def__init__(self,name):print("--init--")s......