背景

我们有很多这样的序列帧:

我这边要把这些序列帧裁切最后合并成gif,以下是我裁切后的png文件:

我一开始选用的是 SixLabors.ImageSharp

这是裁切代码:

using var image = Image.Load("input.jpg");
image.Clone(x => x.Crop(new Rectangle(10, 10, 250, 250)));
image.Save("output.jpg");

gif合成方案1(SixLabors.ImageSharp)

这里直接给出核心代码

public string FrameCombine(List<FrameConfig> frames, int fps)
{
Image firstFrame = null;
var delay = 100 / fps; //根据帧率技术延迟
GifDisposalMethod disposalMethod = GifDisposalMethod.RestoreToBackground; //背景处理方式
string outputPath = null; for (int i = 0; i < frames.Count; i++)
{
Image tempImage = Image.Load(frames[i].Path);
if (i == 0) //第一帧做底图
{
outputPath = Path.Combine(Path.GetDirectoryName(frames[i].Path), "sticker.gif");
if (File.Exists(outputPath))
{
return null;
} firstFrame = tempImage;
firstFrame.Frames.RootFrame.Metadata.GetGifMetadata().FrameDelay = delay;
firstFrame.Metadata.GetGifMetadata().RepeatCount = 0;
}
else
{
//把其他帧合到第一帧上
firstFrame.Frames.AddFrame(tempImage.Frames.RootFrame);
var meta = firstFrame.Frames[i].Metadata.GetGifMetadata();
meta.FrameDelay = delay;
meta.DisposalMethod = disposalMethod;
}
} firstFrame.SaveAsGif(outputPath); return outputPath;
}

最后合成效果(都多多少少有点问题)

大致显示正常(但锯齿和毛边严重)

还有这样的(带莫名的绿色噪点/绿底等):

这样的(莫名灰底):

试了很多方方法,想尽办法调各种属性都不行,看来用SixLabors.ImageSharp比较难解决了;

gif合成方案2(FFmpeg)--推荐

前面SixLabors.ImageSharp方案生成的gif太多问题了,最终是用FFmpeg重新合成才实现的。

步骤

首先,为所有图片生成一个统一的调色板:

ffmpeg -i %02d.png -vf "palettegen" palette.png

然后,使用这个调色板的颜色为基础来生成GIF:

ffmpeg -r 16 -i  %02d.png  -i palette.png -lavfi paletteuse sticker.gif

-r 16 :帧率
-i palette.png :是用于为GIF提供颜色调色板的图像。
-lavfi paletteuse:这是一个复杂的滤镜图描述,指示ffmpeg如何处理输入内容。paletteuse是一个特定的滤镜,它使用前面的name.png输入作为源来生成一个调色板,并使用这个调色板来处理其他输入(在本例中即img_%d.png匹配到的文件)。

将这两条命令合成一条

ffmpeg  -r 16 -i %02d.png -filter_complex "palettegen=stats_mode=single[pal],[0:v][pal]paletteuse" sticker.gif

C#写法(用了这个执行控制台命令的nuget CliWrap

var workDir = Path.GetDirectoryName(frames[0].Path);
var outputPath = Path.Combine(workDir, "sticker.gif");
var param = $" -r {fps} -i %02d.png -filter_complex \"palettegen=stats_mode=single[pal],[0:v][pal]paletteuse\" {outputPath} -y"; try
{
var result = await Cli.Wrap("ffmpeg").WithArguments(param).WithWorkingDirectory(workDir).ExecuteBufferedAsync(); if (result.ExitCode == 0)
{
return outputPath;
} return outputPath;
}
catch (Exception ex)
{
logger.LogError(ex, "FrameCombine2 failed:{0}", frames[0]?.Path);
}

最后展示效果

总结

有的时候其实是比较简单的问题,但如果思路限制在C#的话可能还是比较麻烦的,要去一个个图片处理库试了;

C# .net core中如何将多张png图片合并成一个gif的更多相关文章

  1. ros中同时订阅两个topic(2张图像)合并成一个topic(1张图像)

    2019-12-06 15:42:39 先暂时做个资料保存 要同时用两个红外相机,但是没有做硬件上的 时间戳同步,就是笔记本上同时插着两个相机. 两个topic发布各自相机的图像,然后要有个节点同时订 ...

  2. mysql中的多行查询结果合并成一个

    SELECT GROUP_CONCAT(md.data1) FROM DATA md,contacts cc WHERE md.conskey=cc.id AND md.mimetype_id= 5 ...

  3. gulp-css-spriter 将css代码中的切片图片合并成雪碧图

    NPM地址:https://www.npmjs.com/package/gulp-css-spriter/ 配置gulpfile.js: var gulp = require('gulp'),     ...

  4. MATLAB读取一张RGB图片转成YUV格式

    1.读入照片 控制输出的标志定义 clc;close all;clear YES = 1; NO = 0; %YES表示输出该文件,请用户配置 yuv444_out_txt = 1; yuv444_o ...

  5. php将两张身份证图片合并到一张图

    /** * @desc 合并身份证的正反面到同一张图片 * @author Jimmy * @date 2016-12-33 * @param $imageSrc0 身份证正面 * @param $i ...

  6. python中如何将两个list合并成一个list,不用for语句

    1, add 2, 用list的extend方法,L1.extend(L2),该方法将参数L2的全部元素添加到L1的尾部,例如: 3, 用切片(slice)操作,L1[len(L1):len(L1)] ...

  7. .NET Core 中的日志与分布式链路追踪

    目录 .NET Core 中的日志与分布式链路追踪 .NET Core 中的日志 控制台输出 非侵入式日志 Microsoft.Extensions.Logging ILoggerFactory IL ...

  8. .NET Core中的数据保护组件

    原文地址: PREVENTING INSECURE OBJECT REFERENCES IN ASP.NET CORE 2.0 作者: Tahir Naushad 背景介绍 在 OWASP(开放式 W ...

  9. .net core中的对象池

    asp.net core中通过扩展库的方式提供给了一个标准的对象池ObjectPool,定义在Microsoft.Extensions.ObjectPool.dll 程序集中.它本身是个纯虚的抽象类, ...

  10. 在asp.net core中使用托管服务实现后台任务

    在业务场景中经常需要后台服务不停的或定时处理一些任务,这些任务是不需要及时响应请求的. 在 asp.net中会使用windows服务来处理. 在 asp.net core中,可以使用托管服务来实现,托 ...

随机推荐

  1. Raft 共识算法2-领导者选举

    Raft 共识算法2-领导者选举 Raft算法中译版地址:https://object.redisant.com/doc/raft中译版-2023年4月23日.pdf 英原论文地址:https://r ...

  2. LVGL 定时器

    LVGL 8.0 以后好像取消了自定义任务模块,想要使用多线程只能使用系统的线程. 一.定时器结构体 typedef struct _lv_timer_t { uint32_t period; // ...

  3. QT之Mysql驱动

    错误现象 找不到Mysql驱动 QSqlDatabase: QMYSQL driver not loaded 一.驱动查看 在程序中直接打印QT Creator中现有的驱动,打印方式如下: qDebu ...

  4. 异常值检测算法三:3sigma模型

    离散度 标准差是反应一组数据离散程度最常用的一种量化形式,是表示精确度的重要指标.说起标准差首先得搞清楚它出现的目的.我们使用方法去检测它,但检测方法总是有误差的,所以检测值并不是其真实值.检测值与真 ...

  5. ITIL一定要去认证吗?哪个版本合适

    关于ITIL的演进 ITIL是在演进发展中的,v1并不成功,v2 v3讲究流程与控制,其实都是偏向务虚,理论东西较多,能落地的少或许OGC的专家们自己也发现 光靠口头忽悠并不能说服最终用户接受ITIL ...

  6. 关于ITIL的习惯性误解

    关于ITIL的习惯性误解 1. ITIL是标准?不是!ITIL本质是一套适合西方社会信息化阶段的 模板原版教材 最佳实践(Best Practice),不是标准. 大量的培训师和咨询顾问将其包装成&q ...

  7. Golang ETCD包的安装使用 golang安装etcd第三方库clientv3 报错 解决

    目录 ETCD 官网 视频地址 课件资料 ETCD 日志收集项目 为什么要自己写不用ELK? 项目的架构 上节课项目进度 etcd介绍 安装etcd windows安装 Ubuntu(linux系统) ...

  8. 程序员天天 CURD,怎么才能成长,职业发展的思考(3)

    公司赚钱流程中,你在哪一个环节 思考你在哪一个环节 在一家提供互联网产品或服务的公司中,开发出产品或提供服务,卖产品卖服务给客户,赚取金钱获得利润,有了利润这家公司就能给员工发工资,公司才能存活下去, ...

  9. JDK源码阅读-------自学笔记(十五)(java.lang.Math数学类)

    Math类简介 用于常见的数学方法 如果需要更加强大的数学运算能力,计算高等数学中的相关内容,可以使用apache commons下面的Math类库 常用方法及实战 abs 绝对值 实例: 1 //绝 ...

  10. 在身份认证后建立用户对象ICurrentUser

    app.UseAuthentication(); 这个中间件添加后,他会为HttpContext.User设置一个ClaimsPrincipal对象.里面有身份认证token里面携带的信息. 其访问方 ...