如何使用 OpenCV 变换图像和创建视频

在使用OpenCV时,您最常处理图像。但是,您可能会发现从多个图像创建动画很有用。快速连续显示图像可能会给您不同的见解,或者通过引入时间轴可以更容易地可视化您的工作。

在这篇文章中,您将了解如何在OpenCV中创建视频片段。作为一个示例,您还将学习一些基本的图像处理技术来创建图像。特别是,您将学习:

  • 如何将图像作为Numpy数组进行操作
  • 如何使用OpenCV函数操作图像
  • 如何在OpenCV中创建视频文件

通过我的书《OpenCV 机器学习启动您的项目。它提供了带有可用代码自学教程


让我们开始吧。

如何使用 OpenCV 变换图像和创建视频
照片由 KAL VISUALS 提供。保留部分权利。

概述

这篇文章分为两部分:

  • 肯·伯恩斯效应 (Ken Burns Effect)
  • 写入视频

肯·伯恩斯效应 (Ken Burns Effect)

您将通过阅读其他帖子创建大量图像。这可能是为了可视化您的机器学习项目的一些进展,或者展示计算机视觉技术如何操作您的图像。为了简化操作,您将对输入图像进行最简单的操作:裁剪。

这篇文章的任务是创建**肯·伯恩斯效应 (Ken Burns effect)**。这是一种以电影制片人肯·伯恩斯命名的平移和缩放技术。

肯·伯恩斯效应不是在屏幕上显示一张大型静态照片,而是裁剪细节,然后在图像上平移。
— 维基百科,“肯·伯恩斯效应”

让我们看看如何使用OpenCV在Python代码中创建肯·伯恩斯效应。我们从一张图像开始,例如下面这张您可以从维基百科下载的鸟类图片:

一张《兜帽山唐纳雀 (Buthraupis montana cucullata)》的图片。摄影师:Charles J. Sharp。(CC-BY-SA)

这张图片的分辨率为4563×3042像素。使用OpenCV打开这张图片很简单:

OpenCV读取的图像`img`确实是一个形状为(3042, 4563, 3)的Numpy数组,数据类型为`uint8`(8位无符号整数),因为它是彩色图像,每个像素由0到255之间的BGR值表示。

肯·伯恩斯效应是缩放和平移。视频中的每一帧都是原始图像的裁剪(然后放大以填充屏幕)。给定Numpy数组,裁剪图像很简单,因为Numpy已经提供了切片语法:

图像是一个三维的Numpy数组。前两个维度分别代表高度和宽度(与设置矩阵坐标的方式相同)。因此,您可以使用Numpy切片语法在垂直方向上获取 $y_0$ 到 $y_1$ 像素,在水平方向上获取 $x_0$ 到 $x_1$ 像素(请记住,在矩阵中,坐标从上到下,从左到右编号)。

裁剪图片意味着将尺寸为 $W \times H$ 的图片变为尺寸较小的 $W' \times H'$。为了制作视频,您需要创建固定尺寸的帧。裁剪后的尺寸 $W' \times H'$ 将需要调整大小。此外,为了避免失真,裁剪后的图像还需要保持预定义的纵横比。

要调整图像大小,您可以定义一个新的Numpy数组,然后逐个计算并填充像素值。有许多方法可以计算像素值,例如使用线性插值或直接复制最近的像素。如果您尝试实现调整大小操作,您会发现它并不难,但仍然相当繁琐。因此,更简单的方法是使用OpenCV的本机函数,例如以下内容:

函数`cv2.resize()`接受图像和目标尺寸(作为(宽度, 高度)的元组)并返回一个新的Numpy数组。您可以指定调整大小的算法。上面使用的是线性插值,在大多数情况下看起来不错。

这些基本上是您在OpenCV中操作图像的所有方式,即:

  • 直接操作Numpy数组。这对于需要处理像素级别的简单任务非常有效。
  • 使用OpenCV函数。这更适用于复杂任务,您需要考虑整个图像或者单独操作每个像素效率太低。

有了这些,你就可以制作你的肯·伯恩斯动画了。流程如下:

  1. 给定一张图像(最好是高分辨率的),您需要通过指定起始和结束焦点坐标来定义平移。您还需要定义起始和结束缩放比例。
  2. 您有一个预定义的视频时长和FPS(每秒帧数)。视频的总帧数是时长乘以FPS。
  3. 对于每一帧,计算裁剪坐标。然后将裁剪后的图像调整为视频的目标分辨率。
  4. 所有帧准备好后,您将其写入视频文件。

让我们从常数开始:假设我们将创建一个两秒钟的720p视频(分辨率1280×720),帧率为25 FPS(这有点低,但在视觉上可以接受)。平移将从图像左侧40%、顶部60%的中心开始,并在图像左侧50%、顶部50%的中心结束。缩放将从原始图像的70%开始,然后缩小到100%。

您将多次裁剪图像以创建帧(精确地说,有2×25=50帧)。因此,创建一个裁剪函数是有益的:

这个裁剪函数接受一个图像、像素坐标中的暂定中心位置以及像素数量的宽度和高度。裁剪将确保它不会超出图像边界,因此使用了两个`max()`函数。裁剪是使用Numpy切片语法完成的。

如果您认为当前时间点处于整个持续时间的 $\alpha$% 时,您可以使用仿射变换来计算精确的缩放级别和平移位置。就平移中心(相对于原始宽度和高度的百分比)的相对位置而言,仿射变换给出:

其中`alpha`在0到1之间。类似地,缩放级别为:

给定原始图像大小和比例,您可以通过乘法计算裁剪图像的大小。但是,由于图像的纵横比可能与视频不同,因此您应该调整裁剪尺寸以适应视频的纵横比。假设图像Numpy数组是`img`,并且缩放级别为上面计算的`scale`,则裁剪大小可以计算如下:

以上代码通过比较图像和视频的纵横比(宽度除以高度),并使用缩放级别来确定较小边缘的尺寸,然后根据目标纵横比计算另一个边缘。

一旦您知道需要多少帧,就可以使用for循环以不同的仿射参数`alpha`创建每一帧,该参数可以使用numpy函数`linspace()`获得。完整的代码如下:

最后几行是您如何使用OpenCV写入视频。您创建一个`VideoWriter`对象,并指定FPS和分辨率。然后,您逐帧写入,并释放对象以关闭写入的文件。

创建的视频就像 这个。预览如下:

 

创建视频的预览。观看此视频需要支持的浏览器。

写入视频

从上一节的示例中,您看到了我们如何创建一个`VideoWriter`对象:

与您可能写入图像文件(如JPEG或PNG)的方式不同,OpenCV创建的视频格式不是从文件名推断出来的。它是指定视频格式的第二个参数,即**FourCC**,它是一个由四个字符组成的代码。您可以在以下URL的列表中找到FourCC代码和相应的视频格式:

然而,并非所有的FourCC代码都可以使用。这是因为OpenCV使用FFmpeg工具创建视频。您可以使用以下命令查找支持的视频格式列表:

请确保`ffmpeg`命令与OpenCV使用的相同。另请注意,上述命令的输出只告诉您ffmpeg支持哪些格式,而不是相应的FourCC代码。您需要从其他地方查找代码,例如前面提到的URL。

要检查您是否可以使用特定的FourCC代码,您必须尝试并查看OpenCV是否引发异常:

想开始学习 OpenCV 机器学习吗?

立即参加我的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

总结

在这篇文章中,您学习了如何在OpenCV中创建视频。创建的视频是由一系列帧(即无音频)构建的。每帧都是固定大小的图像。作为一个示例,您学习了如何将肯·伯恩斯效应应用于图片,其中您特别应用了:

  • 使用Numpy切片语法裁剪图像的技术
  • 使用OpenCV函数调整图像大小的技术
  • 使用仿射变换计算缩放和平移参数,并创建视频帧

最后,您使用OpenCV中的`VideoWriter`对象将帧写入视频文件。

开始使用 OpenCV 进行机器学习!

Machine Learning in OpenCV

学习如何在图像处理项目中使用机器学习技术

...以高级方式使用 OpenCV,超越像素处理

在我的新电子书中探索如何实现
OpenCV 机器学习

它提供带有所有可用 Python 代码自学教程,让您从新手成长为专家。它为您提供了
逻辑回归随机森林支持向量机k 均值聚类神经网络等等……所有这些都使用 OpenCV 中的机器学习模块

通过动手练习开启你的深度学习之旅


查看内容

对《如何使用OpenCV转换图像和创建视频》的3条回复

  1. Nuno Pereira 2023年12月2日 上午6:22 #

    非常棒的教程!一个问题:为了对称性,使用以下方式是否更合适?

    y = int(orig_shape[0]*ry)

    而不是

    y = int(orig_shape[0]*rx)?

    • James Carmichael 2023年12月2日 上午11:37 #

      嗨,Nuno……感谢您的反馈!您可能是对的!请继续您的建议,并告诉我们您的发现。

  2. Binyamin 2024年2月23日 上午2:01 #

    非常感谢!
    一篇精彩的帖子。

发表回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。