我最喜欢的摄影技术之一是长时间曝光,即制作照片以显示经过时间的效果的过程,而传统摄影无法捕捉到这种效果。
应用此技术时,水变得如丝般柔滑,夜空中的星星随着地球旋转留下光迹,汽车前灯/尾灯以连续运动的单个波段照亮高速公路。
长时间曝光是一种很棒的技术,但是要捕获这些类型的照片,您需要采取系统的方法:将相机安装在三脚架上,应用各种滤镜,计算曝光值等。更不用说,您需要熟练的摄影师!
可是手机没有此功能呢?自己不会呢?
哈哈,有一种方法可以通过应用图像/帧平均来模拟长时间曝光。通过对给定时间段内从安装的摄像机捕获的图像求平均,我们可以(实际上)模拟长时间曝光。
并且由于视频只是一系列图像,因此我们可以通过将视频中的所有帧平均在一起,轻松地从帧中构建长时间曝光。结果是令人惊叹的长曝光式图像,就像文章开头的图像一样。
这篇博客文章分为三个部分。
实际上,如果您浏览流行的摄影网站,则会发现有关如何使用相机和三脚架手动创建这些类型的效果的教程(可以在此处找到此类教程的一个很好的示例)。
我们今天的目标是简单地实现这种方法,以便我们可以使用Python和OpenCV从输入视频中自动创建长时间曝光的图像。
给定输入视频,我们将所有帧平均在一起(平均加权)以创建长时间曝光效果。
注意:您也可以使用多张图像来创建这种长时间曝光效果,但是由于视频只是一连串图像,因此使用视频来演示此技术会更容易。
首先打开一个名为long_exposure.py
,并插入以下代码
# 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库。
如果没有使用以下命令安装即可。
pip install --upgrade imutils
我们在第7-12行解析两个命令行参数
--video # 视频文件的路径
--output # 输出“长时间曝光”文件的路径+文件名
然后做些初始化步骤:
# 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)...")
在 第16行,我们初始化RGB通道平均值,然后将其合并为最终的长时间曝光图像
我们还初始化第17行的帧总数计数 。
我们正在处理包含所有帧的视频文件,因此有必要打开指向视频捕获的文件指针 stream。
然后计算平均值:
# 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"))
我们将从第27行获取帧,然后将帧分向其各自的BGR通道(第35行)
如果读到了视频文件的末尾,跳出循环即可。
在循环的其余部分,我们将移动计算平均值:
# 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平均值设置为第38-41行上获取的相应第一帧通道 。
否则,我们将在第45-48行计算每个通道的运行平均值 。
我们将计算结果存储在相应的RGB通道平均数组中。
最后,我们增加帧的总数,使我们能够保持运行平均值(第51行)
遍历视频文件中的所有帧后,我们可以将(平均)通道合并为一个图像并将其写入磁盘:
# 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()
在 第54行,我们利用了cv2.merge
函数,同时在列表中指定我们的每个频道平均值。
并将像素转换为[0-255]范围内的整数。
由于处理视频文件需要花费大量CPU时间,因此我们只是将图像保存到磁盘上。
该脚本的最后一步,释放视频流(第58行)。
请注意,每个视频都是通过安装在三脚架上的摄像机捕获的,以确保稳定性。
要创建长时间曝光效果,只需执行以下命令
$ 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进行长时间曝光时,它会给输出带来超现实的,梦幻般的感觉
在今天的博客文章中,我们学习了如何使用OpenCV和图像处理技术来模拟长时间曝光的图像。
为了模拟长时间曝光,我们应用了帧平均,即将一组图像平均在一起的过程。我们假设输入的图像/视频是使用安装的摄像机捕获的(否则生成的输出图像会失真),虽然这不是真正的“长时间曝光”,但效果(在视觉上)非常相似。
译