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

这篇具有很好参考价值的文章主要介绍了通过ffmpeg实现视频背景色替换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

功能实现

本文的测试视频我在B站上随便找了一个,菜虚坤拍篮球绿幕视频素材。截图如下:
ffmpeg替换视频中的绿布,其他,ffmpeg,音视频
首先需要将视频中的绿色改为透明,类似把人物抠出来,这样才能便于修改背景颜色。因为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的参数处理后,效果如下:
ffmpeg替换视频中的绿布,其他,ffmpeg,音视频
因为指定的相似度精度高,所以人物边缘绿色未去除。因为边缘色值或许不是#3fff08。所以我尝试将0.1改为0.18,效果如下:

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

工具制作

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

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

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

为什么需要获取帧率,因为转换后视频默认转为了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就行了,这里就贴代码了。

阈值参数

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


最后结合上面的两条核心命令,将这些参数传入进去就可以了。看似一句话的需求,实际上细节还是比较多的。文章来源地址https://www.toymoban.com/news/detail-840905.html

参考

  • ffmpeg绿幕抠图原理解析

到了这里,关于通过ffmpeg实现视频背景色替换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 通过FFMPEG给视频加字幕

    我们在观看电影或短视频时,一般在视频下发会出现字幕,有些视频还会配中英双语字幕。字幕可以帮助观看人更好的了解视频内容。字幕分为以下三种类型: 外挂字幕:独立的字幕文件,播放视频时把视频和字幕放入同一路径下,也可以在播放器中选择外挂字幕。这样在播

    2024年02月07日
    浏览(36)
  • 通过FFmpeg 来筛选合并视频文件的项目记录

    项目需求 平台通过http下发json格式的消息 程序收到消息后 根据日期时间戳去对应的目录检索是否符合要求的文件 比如某个时间段 检索到之后 将视频片段拼接成一个完整的视频文件  没有的话 根据时间戳判断是否需要等待或者 返回没有检索到  头文件 cpp文件 Http服务用cp

    2024年02月15日
    浏览(37)
  • 使用FFmpeg将本地文件通过UDP推流的音视频

    推流是指将音视频数据通过网络传输到指定的目标端,而FFmpeg是一个功能强大的跨平台多媒体处理工具,可以用于音视频编解码、转码、处理等操作。本文将介绍如何使用FFmpeg将本地文件通过UDP协议进行推流,实现音视频数据的传输。 首先,需要确保已经安装了FFmpeg工具。如

    2024年03月19日
    浏览(69)
  • 【Unity】实用功能开发(一)实现在UI中用RawImage实时展示3D模型(背景透明,并通过UI防止3D场景遮挡)并可以通过分层完成:游戏中的人物状态展示界面,小地图,人物实时头像状态等功能

    有时由于项目效果需要,部分功能的实现受到阻碍,这里收集一些已实现的思路和方法,每次会记录大致需求和遇到的问题,如果有更好的想法,欢迎评论区讨论!!! 目录 功能描述: 需求描述: 实现步骤: ①为需要展示的内容区分层级: ②在场景中添加一个摄像机,并

    2024年02月04日
    浏览(48)
  • 怎么提取视频中的背景音乐?

    当我们在刷视频的时候,有时候听到一个背景音乐很好听,但是又不知道歌名,比如英语歌,这个时候我们很难找到这首歌,相信有很多朋友会遇到这样的问题,不知道怎么弄,下面小编给大家推荐一些方法帮助大家轻松地把视频中的声音提取出来 方法一:使用“智优影”

    2024年02月01日
    浏览(54)
  • ffmpeg将图片压缩成视频过程中的问题记录

    问题描述:服务器集群上在使用如下命令对img_path文件夹下的图片(图片名1.jpg……300.jpg)进行批量合成视频过程中,ffmpeg创建完视频文件后,写入过程中,自动kill,捕获异常为空。 问题原因:集群pods的内存不够,导致ffmpeg在创建完视频文件后,写入过程中内存不够,ffmpeg自动

    2024年02月12日
    浏览(49)
  • ffmpeg 如何剔除掉视频中的水印和马赛克

    FFmpeg 是一款功能强大的用于处理音视频的开源软件,可以用它来剔除视频中的水印和马赛克。具体实现方法如下: 剔除视频中的水印:FFmpeg 可以使用 maskfilter 滤镜来剔除视频中的水印。例如,以下命令可以去除视频中的水印,假设水印区域为 (x,y,w,h): 其中, -filter_complex

    2024年02月11日
    浏览(52)
  • 如何将音视频中的伴奏背景音乐和人声分离?

    有时候我们要将某个视频或者音频文件中的人声或者背景音乐提取出来,用来创作视频或者用来做配乐。这时候,我们就要用到一个功能——“人声分离”,这个功能可以轻松地将人声和背景音乐分离成两条音轨。 伴奏的背景音乐对于一首完整的音乐来说,是很重要的,它能

    2024年02月11日
    浏览(47)
  • 视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用

    在当今这个信息爆炸、沟通无界的时代,视频会议技术已成为连接人与人、企业与企业之间沟通的重要桥梁。正如计算机科学家 Andrew S. Tanenbaum 曾指出:“计算机网络存在的唯一理由是连接人们。” 这一点在视频会议技术的发展中表现得尤为明显。不仅仅是技术的连接,更重

    2024年02月21日
    浏览(46)
  • 20230403在WIN10下通过ffmpeg调用NVIDIA的硬件加速wmv视频转码为MP4格式

    20230403在WIN10下通过ffmpeg调用NVIDIA的硬件加速wmv视频转码为MP4格式 2023/4/3 15:50 最近向学习日语,找到日语发音的视频中,大多数是MP4格式,少量是WMV格式,PR2023貌似不能识别WMV格式。 于是:万能的ffmpeg上场了!   手动指定编解码器 通过 ffmpeg -codecs | findstr \\\"vc1\\\" 查看 vc1 的编解

    2023年04月22日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包