背景

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

我这边要把这些序列帧裁切最后合并成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. WPF开源轻便、快速的桌面启动器

    前言 今天大姚给大家分享一款WPF开源.简单.轻便.快速的桌面启动器(支持多主题.多语言:简体中文.繁体中文.英文等):CurvaLauncher. WPF介绍 WPF 是一个强大的桌面应用程序框架, ...

  2. [Go] 有了 cast 组件, golang 类型转换从此不再困扰

    在 golang 中,参数和返回值之间往往涉及 int.string.[].map 等之间的转换. 如果是手动去处理,一容易出错,二不能兼容多数类型,比较麻烦. 使用 cast,能够让代码更健壮.可维 ...

  3. 开发日志:windows 服务器禁用TLS1.0和TLS1.1协议使网站更安全

    SSL/TLS 的版本 协议 发布时间 状态 SSL 1.0 未公布 未公布 SSL 2.0 1995 年 已于 2011 年弃用 SSL 3.0 1996 年 已于 2015 年弃用 TLS 1.0 ...

  4. 鸿蒙HarmonyOS实战-ArkUI事件(触屏事件)

    前言 触屏事件是指通过触摸屏幕来进行操作和交互的事件.常见的触屏事件包括点击(tap).双击(double tap).长按(long press).滑动(swipe).拖动(drag)等.触屏事件通常 ...

  5. 爽了!免费的SSL,还能自动续期!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 大家好,我是技术UP主小傅哥. 兄弟,当你手里有不少域名,每个域名又配置子域名,那么ssl将是 ...

  6. Java 泛型,这次面试我表现很棒!

    public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryBy ...

  7. 自动生成robot自动化测试用例

    背景:java项目使用swagger管理接口,随着需求的开发接口也有增加,要从swagger界面中去查找出新增的接口是件很费时,效率很低的事情. 适用情况: java项目且适用swagger管理接口 ...

  8. IPD、CMMI、敏捷

    华为公司早在2009年正式发文在全公司现在流程IPD.CMMI的基础上,所有产品线的软件开发团队全面推行敏捷开发.除了华为之外,不仅是互联网企业,现在凡是涉及到软件开发的企业对敏捷都不陌生,那么IPD ...

  9. NumPy 数组切片及数据类型介绍

    NumPy 数组切片 NumPy 数组切片用于从数组中提取子集.它类似于 Python 中的列表切片,但支持多维数组. 一维数组切片 要从一维数组中提取子集,可以使用方括号 [] 并指定切片.切片由起 ...

  10. Gitee千Star优质项目解析: ng-form-element低开引擎解析

    好家伙, 在写项目的时候,我发现自己的平台的组件写的实在是太难看了,于是想去gitee上偷点东西,于是我们本期的受害者出现了 gitee项目地址 https://gitee.com/jjxliu306 ...