利用opencv对图像进行长曝光

2020-09-22 14:40:27 浏览数 (1)

本文翻译自光头哥哥的博客。

【Long exposure with OpenCV and Python】,仅做学习分享。

原文链接:

代码语言:javascript复制
https://www.pyimagesearch.com/2017/08/14/long-exposure-with-opencv-and-python/

我最喜欢的摄影技术之一是长曝光,这是一个创造图片的过程,可以展示时间流逝的影响,这是传统摄影无法捕捉到的。 当应用这一技术时,水变得如丝般光滑,夜空中的星星在地球旋转时留下光迹,汽车前灯或尾灯以单一的连续运动波段照亮高速公路。 长时间曝光是一项很棒的技术,但为了捕捉这类照片,将相机安装在三脚架上,使用各种滤镜,计算曝光值,等等。更不用说,你还需要先成为一个熟练的摄影师!

作为一名计算机视觉研究人员和开发人员,我知道很多关于处理图像的知识——但实际上,我是一个很差劲的摄影师。 幸运的是,有一种方法可以通过应用图像/帧平均来模拟长时间曝光。通过对固定相机在给定时间内拍摄的图像进行平均,我们可以模拟长时间曝光。 由于视频只是一系列图像,我们可以很容易地通过平均视频中的所有帧来构造长曝光。其效果是出乎意料的好,就像这篇博客文章的顶部图片。

这篇博文分为三个部分: 首先,我们将讨论如何通过帧平均模拟长曝光。 然后,我们将编写Python和OpenCV代码,利用输入视频创建类似长曝光的图片效果。 最后,我们将对一些示例视频应用代码来测试其效果。

一:通过图像/帧平均模拟长曝光

通过平均来模拟长时间曝光的想法并不是什么新想法。 事实上,如果你浏览流行的摄影网站,你会发现很多教你如何使用相机和三脚架手工创建长曝光图片的教程。

我们今天的目标是简单地实现这种效果,使用Python和OpenCV从输入视频中自动创建类似于长曝光的图像。对于输入的视频,我们会将所有帧平均起来(相等地加权),以产生长曝光效果。 注意:你也可以使用多张图片来创建这种长曝光效果,但由于一个视频是一系列图片,使用视频来演示这项技术更容易。在将该技术应用到你自己的文件时,需要注意这一点。

二:利用OpenCV实现长时间曝光模拟

让我们首先打开一个名为long_exposure.py的新文件,并插入以下代码:

代码语言:javascript复制
# import the necessary packages
import argparse
import imutils
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", required=True,
  help="path to input video file")
ap.add_argument("-o", "--output", required=True,
  help="path to output 'long exposure'")
args = vars(ap.parse_args())

第2-4行处理我们的导入视频,你将需要imutils和OpenCV。 如果你的环境中还没有安装imutils,只需使用pip:

代码语言:javascript复制
$ pip install --upgrade imutils

我们在第7-12行解析我们的两个命令行参数: --video:视频文件的路径。 --output:输出长曝光图片的路径 文件名。 接下来,我们将执行一些初始化步骤:

代码语言:javascript复制
# initialize the Red, Green, and Blue channel averages, along with
# the total number of frames read from the file
(rAvg, gAvg, bAvg) = (None, None, None)
total = 0
# open a pointer to the video file
print("[INFO] opening video file pointer...")
stream = cv2.VideoCapture(args["video"])
print("[INFO] computing frame averages (this will take awhile)...")

在第3行,我们初始化RGB通道的平均,我们稍后将它合并到最终的长曝光图像。 我们还在第4行上初始化了帧总数的计数。 在本教程中,我们使用的是一个包含所有帧的视频文件,因此有必要在第8行打开一个指向视频捕获流的文件指针。 现在让我们开始我们的循环,它将计算平均值:

代码语言:javascript复制
# loop over frames from the video file stream
while True:
  # grab the frame from the file stream
  (grabbed, frame) = stream.read()
  # if the frame was not grabbed, then we have reached the end of
  # the sfile
  if not grabbed:
    break
  # otherwise, split the frmae into its respective channels
  (B, G, R) = cv2.split(frame.astype("float"))

在我们的循环中,我们将从视频流中获取帧(第4行),并将帧分割成各自的BGR通道(第12行)。注意中间的退出条件——如果一个帧没有从流中抓取,我们就在视频文件的末尾,我们将跳出循环(第8行和第9行)。 在循环的其余部分,我们将执行运行的平均计算:

代码语言:javascript复制
  # if the frame averages are None, initialize them
  if rAvg is None:
    rAvg = R
    bAvg = B
    gAvg = G
  # otherwise, compute the weighted average between the history of
  # frames and the current frames
  else:
    rAvg = ((total * rAvg)   (1 * R)) / (total   1.0)
    gAvg = ((total * gAvg)   (1 * G)) / (total   1.0)
    bAvg = ((total * bAvg)   (1 * B)) / (total   1.0)
  # increment the total number of frames read thus far
  total  = 1

如果这是第一次迭代,我们将使用视频第一帧图像的RGB通道像素值来初始化(只有在第一次循环时才需要这样做,因此使用If语句)。 否则,我们将计算(8-11行)每个通道的平均值。平均计算非常简单——我们用帧的总数total乘以各个通道的平均值,然后加上当前帧各个通道的值,然后将结果除以帧数(我们在分母上加1,因为当前图像是新的一帧)。最后帧总数total变量加1。

一旦我们循环了视频文件中的所有帧,我们可以合并(平均)通道到一个图像并将结果写入磁盘:

代码语言:javascript复制
# merge the RGB averages together and write the output image to disk
avg = cv2.merge([bAvg, gAvg, rAvg]).astype("uint8")
cv2.imwrite(args["output"], avg)
# do a bit of cleanup on the file pointer
stream.release()

在第2行,我们使用了方便的cv2,调用通道合并函数merge( ),由于这些数组包含浮点数(因为它们是所有帧的平均值),我们附加astype("uint8")来将像素转换为范围为[0-255]的整数。

三:测试结果

让我们通过处理两个示例视频来看看程序的实际操作效果。请注意,每个视频都是由安装在三脚架上的摄像机拍摄的,以确保视频的稳定性。

我们的第一个例子是一个15秒的水流过岩石的视频:我包含了一个视频帧的样本如下:

要创建长曝光效果,只需执行以下命令:

代码语言:javascript复制
$ time python long_exposure.py --video videos/river_01.mov --output river_01.png 
[INFO] opening video file pointer...
[INFO] computing frame averages (this will take awhile)...
real  2m1.710s
user  0m50.959s
sys    0m40.207s

请注意,由于平均过程,水被混合成丝般柔滑的形式。 让我们继续第二个河流的例子:

处理效果:

总结

在今天的博客文章中,我们学习了如何使用OpenCV和图像处理技术来模拟长时间曝光的图像。

为了模拟长曝光,我们应用了帧平均,这是将一组图像平均在一起的过程。我们假设我们的输入图像/视频是使用安装的摄像机捕获的(否则结果输出图像将会失真)。 虽然这不是真正的“长曝光”,但效果(视觉上)相当相似。更重要的是,这可以让你不需要专业摄影师以及投资就可以应用长曝光效果。

0 人点赞