当前位置: 首页 > news >正文

通过ffmpeg实现视频背景色替换

最近遇到一个需求,希望可以将素材视频的绿幕背景替换为指定的颜色,然后通过裁剪,拼接等处理制作一个新的视频。所以替换背景色成为了重要的一环,看能否通过ffmpeg来实现。通过一番搜索尝试,发现方案可行。下面我整理一下实现方法。

功能实现

本文的测试视频我在B站上随便找了一个,菜虚坤拍篮球绿幕视频素材。截图如下:
在这里插入图片描述
首先需要将视频中的绿色改为透明,类似把人物抠出来,这样才能便于修改背景颜色。因为mov格式视频支持透明通道,所以第一步需要在去除背景色的同时将视频保存为mov格式。所以需要使用到chromakey滤镜。

ffmpeg -i input.mp4 -vf "chromakey=#3fff08:0.1:0.04" -c:v qtrle -c:a copy output.mov
  • #3fff08是绿幕的颜色,也就是需要替换为透明的颜色。
  • 0.1是相似度(similarity)参数。这个参数决定了颜色匹配的严格程度。值越小,匹配的颜色范围越窄,也就是说,只有非常接近指定颜色的像素才会被视为透明。值越大,匹配的颜色范围越宽,也就是说,即使颜色和指定颜色有一些差距,也会被视为透明。
  • 0.04是混合度(blend)参数。这个参数决定了边缘像素的处理方式。值越小,边缘像素的处理越严格,可能会导致边缘部分出现锐利的边缘。值越大,边缘像素的处理越宽松,可能会导致边缘部分出现柔和的过渡。

然后修改颜色:

ffmpeg -i output.mov -vf "color=color=#2B2D30:size=1920x1080 [bg]; [bg][0:v] overlay=shortest=1" output2.mp4
  • #2B2D30是需要修改的视频背景色。
  • 1920x1080是视频的分辨率,也就是给视频一个这么大的背景。

我们以上面0.1和0.04的参数处理后,效果如下:
在这里插入图片描述
因为指定的相似度精度高,所以人物边缘绿色未去除。因为边缘色值或许不是#3fff08。所以我尝试将0.1改为0.18,效果如下:

在这里插入图片描述
效果好了许多,按照这个思路,我尝试到0.3,感觉效果就已经比较好了。
在这里插入图片描述
需要注意的是,这两个参数不是越大越好,过高的值会匹配更多的颜色,会导致整个视频都透明了。比如我试了0.3和0.1的组合,效果如下:
在这里插入图片描述
发现画面整个变暗了,因为背景是灰色,混合度过高,所以就像是蒙了一层灰色。所以这两个参数的具体值取决于视频和绿幕的特定情况。需要根据实际效果进行调整,以获得最佳的绿幕去除效果。

工具制作

如果只是功能实现,那么上面的两条命令基本已经够了。但是要将这一功能做成工具,就需要更近一步。

首先命令中的参数都需要动态获取。

  • 获取原视频的背景色。
  • 获取原视频的分辨率,帧率。
  • 两个阈值参数可以输入。

为什么需要获取帧率,因为转换后视频默认转为了25帧,如果你不想影响原视频帧率,就需要指定帧率,例如指定30帧:

ffmpeg -i output.mov -vf "color=color=#2B2D30:size=1920x1080 [bg]; [bg][0:v] overlay=shortest=1" -r 30 output2.mp4

另外,码率也是类似。

获取背景色

ffmpeg -ss 0.1 -i input.mp4 -vframes 1 output.jpg

首先通过命令获取一张视频的截图,这里取0.1s的位置。

然后获取图片中颜色最多的色值。我这里是用flutter实现的,代码如下:

  /// 获取图片数据Future<ui.Image?> loadImage(File file) async {final Completer<ui.Image> completer = Completer();ImageProvider imageProvider = FileImage(file);ImageStreamListener listener = ImageStreamListener((info, _) async {completer.complete(info.image);});final ImageStream stream = imageProvider.resolve(const ImageConfiguration());stream.addListener(listener);try {await completer.future;} catch (e) {debugPrint("Error loading image: $e");} finally {stream.removeListener(listener);}return completer.isCompleted ? completer.future : null;}/// 获取图片中颜色最多的色值Future<Color?> getMostCommonColor(ui.Image? image) async {if (image == null) {return null;}Uint8List bytes = await image.toByteData().then((data) => data!.buffer.asUint8List());final colorCount = <Color, int>{};for (int i = 0; i < bytes.lengthInBytes; i += 4) {final red = bytes[i];final green = bytes[i + 1];final blue = bytes[i + 2];final alpha = bytes[i + 3];final key = Color.fromARGB(alpha, red, green, blue);if (colorCount.containsKey(key)) {colorCount[key] = colorCount[key]! + 1;} else {colorCount[key] = 1;}}Color? mostCommonColor;int maxCount = 0;colorCount.forEach((color, count) {if (count > maxCount) {mostCommonColor = color;maxCount = count;}});return mostCommonColor;}

这是一种思路,当然也可以获取指定位置的颜色,毕竟背景色都是一致的,如果不一致,那么替换的效果也会打折扣,所以这种方法相对比较简单一些。

Future<Color?> getPixelColor(ui.Image? image, int x, int y) async {if (image == null) {return null;}final byteData = await image.toByteData();if (byteData == null) {return null;}final width = image.width;final pixelOffset = (y * width + x) * 4;final r = byteData.getUint8(pixelOffset);final g = byteData.getUint8(pixelOffset + 1);final b = byteData.getUint8(pixelOffset + 2);final a = byteData.getUint8(pixelOffset + 3);return Color.fromARGB(a, r, g, b);}

这里我获取到的色值是16进制的,例如Color(0xff14ff09),我需要转成字符#14ff09

Color color = Color(0xff14ff09);
String colorStr = '#${color.value.toRadixString(16).substring(2)}';

获取视频的分辨率,帧率

获取命令:

ffprobe -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate -of csv=p=0 input.mp4

这里使用csv=p=0让结果用逗号拼接返回,例如:1920,1080,30/1

然后我们用代码处理这个字符串,获取最终想要的 1920x108030就行了,这里就贴代码了。

阈值参数

最后页面上加两个输入框,输入这两个阈值参数就万事具备了。


最后结合上面的两条核心命令,将这些参数传入进去就可以了。看似一句话的需求,实际上细节还是比较多的。

参考

  • ffmpeg绿幕抠图原理解析

相关文章:

通过ffmpeg实现视频背景色替换

最近遇到一个需求&#xff0c;希望可以将素材视频的绿幕背景替换为指定的颜色&#xff0c;然后通过裁剪&#xff0c;拼接等处理制作一个新的视频。所以替换背景色成为了重要的一环&#xff0c;看能否通过ffmpeg来实现。通过一番搜索尝试&#xff0c;发现方案可行。下面我整理一…...

后轮位置反馈控制与算法仿真实现

文章目录 1. 后轮反馈控制2. 算法原理3. 算法和仿真实现 1. 后轮反馈控制 后轮反馈控制&#xff08;Rear wheel feedback&#xff09;算法是利用后轮中心的跟踪偏差来进行转向控制量计算的方法&#xff0c;属于Frenet坐标系的一个应用。通过选择合适的李雅普诺夫函数设计控制率…...

实战 vue3 使用百度编辑器ueditor

前言 在开发项目由于需求vue自带对编辑器不能满足使用&#xff0c;所以改为百度编辑器&#xff0c;但是在网上搜索发现都讲得非常乱&#xff0c;所以写一篇使用流程的文章 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、下载ueditor编辑器 一个“…...

N种方法解决1(CTF)

这里遇到的问题&#xff1a;一开始采用的base64解码平台有问题&#xff1b;默认解密出的格式为GBK格式&#xff1b;直接复制粘贴发现无法还原图片&#xff1b;又尝试了其他编码的&#xff1b;发现只有hex格式可以保证图片正常还原&#xff1b; 图片是以二进制存储的&#xff1…...

Istio实战:Istio Kiali部署与验证

目录 前言一、Istio安装小插曲 注意事项 二、Kiali安装三、Istio测试参考资料 前言 前几天我就开始捣腾Istio。前几天在执行istioctl install --set profiledemo -y 的时候老是在第二步就报错了&#xff0c;开始我用的istio版本是1.6.8。 后面查看k8s与istio的版本对应关系后发…...

ASPxGridView中使用PopupEditForm表单字段联动填充

c#中devexpress的控件ASPxGridView中使用PopupEditForm表单字段联动填充 //选择项目名称&#xff0c;自动填充项目编号 <Columns><dx:GridViewDataTextColumn FieldName"id" ReadOnly"True" VisibleIndex"0" Visible"False"…...

基于Pytorch的猫狗图片分类【深度学习CNN】

猫狗分类来源于Kaggle上的一个入门竞赛——Dogs vs Cats。为了加深对CNN的理解&#xff0c;基于Pytorch复现了LeNet,AlexNet,ResNet等经典CNN模型&#xff0c;源代码放在GitHub上&#xff0c;地址传送点击此处。项目大纲如下&#xff1a; 文章目录 一、问题描述二、数据集处理…...

flutter sliver 多种滚动组合开发指南

flutter sliver 多种滚动组合开发指南 视频 https://youtu.be/4mho1kZ_YQU https://www.bilibili.com/video/BV1WW4y1d7ZC/ 前言 有不少同学工作中遇到需要把几个不同滚动行为组件&#xff08;顶部 appBar、内容固定块、tabBar 切换、tabBarView视图、自适应高度、横向滚动&a…...

kafka生产者2

1.数据可靠 • 0&#xff1a;生产者发送过来的数据&#xff0c;不需要等数据落盘应答。 风险&#xff1a;leader挂了之后&#xff0c;follower还没有收到消息。。。。 • 1&#xff1a;生产者发送过来的数据&#xff0c;Leader收到数据后应答。 风险&#xff1a;leader应答…...

【LNMP】云导航项目部署及环境搭建(复杂)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍1.1项目环境架构LNMP1.2项目代码说明 二、项目环境搭建2.1 Nginx安装2.2 php安装2.3 nginx配置和php配置2.3.1 修改nginx文件2.3.2 修改vim /etc/p…...

nginx之状态页 日志分割 自定义图表 证书

5.1 网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机的状态 server{…...

数字人的未来:数字人对话系统 Linly-Talker + 克隆语音 GPT-SoVITS

&#x1f680;数字人的未来&#xff1a;数字人对话系统 Linly-Talker 克隆语音 GPT-SoVITS https://github.com/Kedreamix/Linly-Talker 2023.12 更新 &#x1f4c6; 用户可以上传任意图片进行对话 2024.01 更新 &#x1f4c6; 令人兴奋的消息&#xff01;我现在已经将强…...

SpringMVC 学习(五)之域对象

目录 1 域对象介绍 2 向 request 域对象共享数据 2.1 通过 ServletAPI (HttpServletRequest) 向 request 域对象共享数据 2.2 通过 ModelAndView 向 request 域对象共享数据 2.3 通过 Model 向 request 域对象共享数据 2.4 通过 map 向 request 域对象共享数据 2.5 通过…...

✅技术社区项目—JWT身份验证

通用的JWT鉴权方案 JWT鉴权流程 基本流程分三步: ● 用户登录成功之后&#xff0c;后端将生成的jwt返回给前端&#xff0c;然后前端将其保存在本地缓存; ● 之后前端与后端的交互时&#xff0c;都将iwt放在请求头中&#xff0c;比如可以将其放在Http的身份认证的请求头 Author…...

5.2 Ajax 数据爬取实战

目录 1. 实战内容 2、Ajax 分析 3、爬取内容 4、存入MySQL 数据库 4.1 创建相关表 4.2 数据插入表中 5、总代码与结果 1. 实战内容 爬取Scrape | Movie的所有电影详情页的电影名、类别、时长、上映地及时间、简介、评分&#xff0c;并将这些内容存入MySQL数据库中。 2、…...

276.【华为OD机试真题】矩阵匹配(二分法—JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-矩阵匹配二.解题思路三.题解代码Python题解代码…...

java——多线程基础

目录 线程的概述多线程的创建方式一&#xff1a;继承Thread类方式二&#xff1a;实现Runnable接口方式三&#xff1a;利用Callable接口、FutureTask类来实现。Thread常用的方法 线程安全问题线程安全问题概述线程安全问题案例取钱案例描述模拟代码如下&#xff1a;执行结果 线程…...

Python服务器监测测试策略与工具:确保应用的高可用性!

在构建高可用性的应用程序时&#xff0c;服务器监测测试是至关重要的一环。Python作为一种强大的编程语言&#xff0c;提供了丰富的工具和库来帮助我们进行服务器监测测试。本文将介绍一些关键的策略和工具&#xff0c;帮助你确保应用的高可用性。 1. 监测策略的制定&#xff…...

Spring Security源码学习

Spring Security本质是一个过滤器链 过滤器链本质是责任链设计模型 1. HttpSecurity 【第五篇】深入理解HttpSecurity的设计-腾讯云开发者社区-腾讯云 在以前spring security也是采用xml配置的方式&#xff0c;在<http>标签中配置http请求相关的配置&#xff0c;如用户…...

大数据面试总结三

1、hdfs作为分布式存储系统&#xff0c;底层的实现的方式&#xff08;可能不正确&#xff09; 1、底层是一个分布式存储的&#xff0c;底层会将数据进行切分多个block块&#xff08;128M&#xff09;&#xff0c;并存储在不同的节点上面&#xff0c;这种分布式方式有助于提高数…...

3分钟掌握缠论可视化:通达信智能技术分析插件终极指南

3分钟掌握缠论可视化&#xff1a;通达信智能技术分析插件终极指南 【免费下载链接】Indicator 通达信缠论可视化分析插件 项目地址: https://gitcode.com/gh_mirrors/ind/Indicator 还在为复杂的缠论理论头疼吗&#xff1f;还在手工画线分析K线图吗&#xff1f;CZSC缠论…...

Node.js 与前端 JavaScript 的区别:不止运行环境,底层完全不一样

很多开发者误以为 Node.js 和浏览器 JavaScript 只是运行地方不同、语法一样&#xff0c;实际二者虽共用 ECMAScript 语法规范&#xff0c;但在全局对象、API 能力、DOM/BOM、模块系统、事件循环、系统权限、应用场景等方面存在本质差异。本文从技术底层全面对比&#xff0c;帮…...

Deep Agents:开箱即用的AI智能体框架,快速构建自主规划与执行应用

1. 项目概述&#xff1a;一个开箱即用的AI智能体框架如果你正在尝试构建一个能自主规划、读写文件、执行命令的AI智能体&#xff0c;大概率会经历一个相当繁琐的过程&#xff1a;先选一个LLM模型&#xff0c;然后设计一套复杂的提示词&#xff08;Prompt&#xff09;来教它如何…...

AD9361快速切频点秘籍:不用复杂计算,一张2400-2480MHz的查表配置表直接拿去用

AD9361射频芯片极速切频实战&#xff1a;2400-2480MHz预计算配置表与查表法优化 在Wi-Fi 6E和蓝牙5.3设备爆发式增长的今天&#xff0c;射频工程师每天需要处理数百次频段切换测试。传统AD9361配置流程中&#xff0c;每次切换频点都要重新计算VCO分频比、电荷泵电流等12个关键参…...

手把手教你写一个能自动上网写研报的 Research Agent

手把手教你写一个能自动上网写研报的 Research Agent 引言 痛点引入 如果你是券商研究员、行业分析师、高校商科学生,或者企业战略岗的从业者,一定对「写研报」这件事的痛苦深有体会: 查资料耗时:一篇中等深度的行业研报,至少需要翻阅30+权威来源的信息,包括工信部政策…...

GDB调试实战:如何像本地变量一样轻松查看函数参数和结构体成员(附常用命令清单)

GDB调试实战&#xff1a;像本地变量一样高效查看函数参数与复杂数据结构 调试大型C/C项目时&#xff0c;最令人头疼的莫过于面对层层嵌套的函数调用和包含数十个成员的结构体。传统调试方式往往让我们陷入内存地址的泥潭&#xff0c;而GDB提供的诸多高级功能可以彻底改变这一局…...

通过Taotoken CLI工具一键配置团队开发环境与统一API密钥

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 通过Taotoken CLI工具一键配置团队开发环境与统一API密钥 基础教程类&#xff0c;介绍如何利用Taotoken提供的命令行工具&#xff…...

3步搞定安卓应用Windows安装:告别臃肿模拟器的终极解决方案

3步搞定安卓应用Windows安装&#xff1a;告别臃肿模拟器的终极解决方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否厌倦了那些占用大量系统资源、启动缓慢的…...

1.8.2 掌握Scala类与对象 - 单例对象与伴生对象

本次实战通过三个案例深入解析了 Scala 中 object 的核心机制&#xff0c;展示了其如何替代 Java 的 static 关键字。首先&#xff0c;通过 MathUtils 定义了存放常量与工具方法的独立单例对象&#xff1b;其次&#xff0c;利用 Person 类与其同名对象演示了“伴生对象”特性&a…...

Awesome BigData实时数据集成平台:CDC连接器与数据同步工具终极指南

Awesome BigData实时数据集成平台&#xff1a;CDC连接器与数据同步工具终极指南 【免费下载链接】awesome-bigdata A curated list of awesome big data frameworks, ressources and other awesomeness. 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-bigdata G…...