从视频的半恒定帧中检测固定模板图像

信息处理 图像处理 算法
2021-12-20 20:32:38

我正在寻找许多视频来处理不同的视频游戏,以检测其中的各种“状态”。

我要解决的第一款游戏是《超级街头霸王4 》的任何版本。

在其中,我想检测“vs”字符屏幕何时出现。这是视频一帧的示例:

Akuma vs. Ryu - SSF4
(取自该视频约 10 秒标记

如果我可以检测到“vs”,那么我就可以检测到视频帧确实是“vs”屏幕,这可以让我查找其他信息(现在,假设我将使用它来检测视频中比赛即将开始的时间戳)。

也就是说,以下是我将要处理的视频中的帧的假设(这不是唯一的视频,有数千个,如果不是数万或数十万个视频,但处理规模的问题许多视频是一个完全不同的领域):

  • 我更喜欢(但不是必需的)以可靠的结果处理可能的最低分辨率图像(较低的分辨率 = 更快的处理时间)。上面的图片是 480 x 270 像素(取自YouTube 视频,带有fmt18),但它们可能有不同的尺寸(我得到了fmt18 的 YouTube 视频,但尺寸为 640 x 360 像素)。
  • 大多数视频将是直接馈送
  • 大多数视频的宽高比为 16:9
  • 带红色的背景将是动画的,但通常在橙红色范围内(它是火焰)
  • 有时会在“vs”的下部有一个淡入淡出的徽章来表示一个版本(这很重要,但不是现在),这可能会混淆“vs”,如下所示:

Sagat vs. Adon - SSF4:AE 2012
(取自该视频约 3 秒标记;另请注意,以上是 640 x 360 像素的分辨率)

  • “vs”的大小和位置将大致相同(我还没有验证这一点,但我知道它不会移动)与其他直接馈送视频成比例
  • 角色将从每边超过 30 个的池中选择(换句话说,框架的那些区域会有所不同)
  • 这些视频的长度通常在 2 到 4 分钟之间,大约在 4,000 到 6,00 帧之间。但是,可能会有更长的视频(可能是两个小时),其中插入了各种其他游戏和真人动作。这些视频并不那么重要,但如果解决方案告诉我某个游戏在更大的整体视频中弹出的位置,那就太好了
  • 捕获的原始分辨率为 720p,因此“vs”的基线图像可以被认为是“原始”尺寸。

最终,我希望在 .NET 中编写这个管道,但这并不是重要,这里的概念验证以及对所涉及技术的理解更为重要,以便我可以为 .NET 翻译和优化它以及相同类型的其他游戏的其他视频(如果我能找出重要的区别,比如Ultimate Marvel vs. Capcom 3Street Fighter x TekkenBlazBlue: Continuum Shift等视频)。

我还在Mathematica 中试水,并且拥有家庭版 8.0,因此在该环境中进行概念验证也非常受欢迎。

1个回答

如果“VS”几乎相同(除了第二个示例中的一些徽章覆盖),您可以使用简单的互相关来检测视频帧中模板的存在。在 MATLAB on Stack Overflow 上回答了一个类似的问题。您可以使用 Photoshop 中的“魔术棒”工具从框架中选择“VS”来创建模板。我已经这样做并将图像二值化以获得此模板

查看两个图像中的不同颜色通道 (RGB),红色通道似乎是检测模板的最佳选择。

在此处输入图像描述

您现在可以将红色通道与您的二值化模板进行交叉关联,并且您应该在模板的位置获得一个峰值。我也选择对红色模板进行阈值化和二值化,尽管您可以不这样做就检测到它。我更喜欢使用距离函数而不是原始的互相关值,因为它对误报更加稳健。我不知道 C#/.NET,但这里是 Mathematica 中方法的概述:

image = Import["http://i.stack.imgur.com/7RwAh.png"];
ImageCorrelate[ Binarize[ColorSeparate[image][[1]], 0.1], vsTemplate, 
   NormalizedSquaredEuclideanDistance] // Binarize[#, 0.2] & // ColorNegate

它为您提供以下内容。白点标记了两幅图像中距离最小的区域

在此处输入图像描述 在此处输入图像描述

然后,您可以根据需要在下一步中使用上述内容。请注意,通常,互相关会导致悬垂。换句话说(使用 1D 示例),如果您要对N点信号与M第一点,你会得到一个结果N+M1点长。Mathematica 的实现会为您处理悬垂问题。但是,我不知道 C# 是做什么的,您可能要记住这一点(MATLAB 不这样做,我必须在上面的链接答案中说明这一点)。

您还可以在此基础上构建自己的更强大的阈值标准。现在,为了他人的利益,我将只强调检测:

在此处输入图像描述 在此处输入图像描述

您可以使用组合功能生成上述内容:

detectVS[i_Image] := 
 Module[{mask = 
    ImageCorrelate[ Binarize[ColorSeparate[i][[1]], 0.1], vsTemplate, 
       NormalizedSquaredEuclideanDistance] ~Binarize~ 0.2 // 
     ColorNegate},

  ColorConvert[i, "Grayscale"]~ImageAdd~ 
   ImageMultiply[i, Image[mask]~Dilation~ DiskMatrix@100]
  ]

这里有很多改进的潜力。我是图像处理的业余爱好者,所以我不知道最快的算法是什么。但是,您可以研究以下几点:

  1. 如果 VS 在每个视频中的位置大致相同,则无需使用整个图像进行互相关 - 您只需选择中间的一个框并使用它即可。
  2. 对于每一帧,这可能是一项昂贵的操作。但是,查看您的视频,您有大约 4 秒多一点的帧,其中显示了 VS 和角色名称。因此,我建议您每秒或最多每 2 秒分析一帧,从而保证您将降落在带有 VS 的帧上。一旦检测到 VS,您就可以开始处理每个连续的帧以进行下一部分处理。
  3. 在合理的范围内,这个过程对于大小的变化应该是稳健的,即,您可以对小图像进行互相关,但您需要一个合适的模板来匹配。如果您知道您的图像将采用某些设置/标准尺寸,那么您可以为每个图像创建模板并根据图像尺寸选择适当的模板。
  4. 我选择的阈值是反复试验,但它们似乎确实适用于上面的两张图片和其他相关的 youtube 视频,它们可能适用于其中的大多数。更专业的方法是将其分成块并查看直方图以推断它是否属于 VS——也许是贝叶斯分类器。但是,请绝对确定您需要在开始之前执行此操作。在我看来,它很简单,你不需要它。