简体   繁体   English

模拟视频帧OpenCV的长时间曝光

[英]Simulate long exposure from video frames OpenCV

I am trying to simulate a long exposure photo by combining images(frames) into one image and by performing operations based on a preset alpha. 我试图通过将图像(帧)组合成一个图像并通过基于预设的alpha执行操作来模拟长曝光照片。 I am doing this on an iPhone, and I currently have the length of the video set to 1 second(30 frames). 我在iPhone上这样做,我目前将视频长度设置为1秒(30帧)。 The alpha is set to 1.0/frameCount however I hard coded in 30 to represent one second of 30 FPS video capture. alpha设置为1.0/frameCount但是我在30中硬编码表示30 FPS视频捕获的一秒。 I stop the operations once it has reached one second of video/30 frames. 一旦达到一秒视频/ 30帧,我就停止操作。 The idea is the user can set a timer for x seconds and I will do the math to figure out how many frames to allow. 这个想法是用户可以设置一个x秒的计时器,我将做数学计算,以确定允许多少帧。

Here is the code I am using: 这是我正在使用的代码:

- (void)processImage:(Mat&)image
{

    if (_isRecording) {

        // first frame

        double alpha = 1.0/30;

        if (_frameCount == 0) {

            _exposed = image;
            _frameCount++;
        } else {

            Mat exposed = _exposed.clone();
            addWeighted(exposed, alpha, image, 1.0 - alpha, 0.0, _exposed);
            _frameCount++;
        }

        // stop and save image
        if (_frameCount == 30) {
            _isRecording = NO;
            _frameCount = 0;

            cvtColor(_exposed, _exposed, CV_BGRA2RGB, 30);
            UIImage *exposed = [LEMatConverter UIImageFromCVMat:_exposed];
            UIImageWriteToSavedPhotosAlbum(exposed, nil, nil, nil);
            NSLog(@"saved");
        }
    }
}

When I run this code I basically get back a still image that looks as if it is a single frame. 当我运行这段代码时,我基本上会找回一张看起来好像是单帧的静止图像。 Here is an example: 这是一个例子:

在此输入图像描述

Does anyone know how I can produce the desired effect of a long exposure image from video frames given I know how many frames there will be? 有谁知道如何从视频帧中产生长曝光图像的预期效果我知道会有多少帧?

First of all, (probably this is not your case, as you pointed out that you are working on a video and not a camera) if you base your code on the value of the frame rate, be sure that 30fps is the effective value and not the maximum one. 首先,(可能这不是你的情况,因为你指出你正在处理视频而不是相机)如果你的代码基于帧速率的值,请确保30fps是有效值,不是最大的一个。 Sometimes cameras automatically adjust that number based on the amount of light they get from the environment. 有时,相机会根据从环境中获得的光量自动调整该数量。 If it is dark, then the exposure time is increased and therefore the framerate is diminished. 如果天黑,则曝光时间增加,因此帧速率降低。

Second point, it is really hard to simulate the real mechanism of photo exposure given a bunch of pixels. 第二点,给出一堆像素很难模拟照片曝光的真实机制。 Imagine you want to double the exposure time, this should be simulated by two consecutive frames. 想象一下,你想要将曝光时间加倍,这应该通过两个连续的帧来模拟。 In the real world doubling the exposure time means that the shutter speed is halved and so twice as much light hits the sensor or film, the result is a brighter image. 在现实世界中,曝光时间加倍意味着快门速度减半,因此光线照射到传感器或胶片的两倍,结果是图像更亮。
How do you simulate this? 你怎么模拟这个? Consider for simplicity the case of two quite bright grayscale images you want to merge. 为简单起见,请考虑要合并的两个非常明亮的灰度图像。 If in a given point the pixel values are, say, 180 and 181 what is the resulting value? 如果在给定点,像素值是180和181,那么结果值是多少? The first answer would be 180+181, but pixel intensities ranges between 0 and 255, so it has to be truncated at 255. The real camera with increased exposure probably would behave differently, not reaching the maximum value. 第一个答案是180 + 181,但像素强度范围在0到255之间,因此必须在255处截断。曝光增加的真实相机可能表现不同,但未达到最大值。

Now I'll consider you code. 现在我会考虑你的代码。
The first time you process an image (ie run the function), you simply store the frame in variable _exposed. 第一次处理图像(即运行函数)时,只需将帧存储在变量_exposed中。
The second time you blend 29/30 of the new frame and 1/30 of the previously stored image. 第二次混合29/30的新帧和1/30的先前存储的图像。
The third time 29/30 of the third frame with the result of previous operation. 第三帧的第三次29/30与前一次操作的结果。 This results in placing a fading weight on the first frame which is virtually disappeared. 这导致在第一帧上放置褪色重量,这实际上消失了。
The last time you call the function, again, you sum up 29/30 of the last frame and 1/30 of the previous result. 上次再次调用该函数时,您总结了最后一帧的29/30和前一个结果的1/30。 In turn this means that the effect of the first frames is virtually disappeared and even the previous one counts only for a share of 29/(30x30). 反过来,这意味着第一帧的效果几乎消失,甚至前一帧的效果仅计入29 /(30x30)的份额。 The image you get is just the last frame with a slight blur coming from the previous frames. 您获得的图像只是前一帧中带有轻微模糊的最后一帧。
How do you obtain a simulation of exposure? 你如何获得曝光模拟? If you simply want to average 30 frames you have to replace these lines: 如果你只想平均30帧,你必须替换这些线:

    if (_frameCount == 0) {
       _exposed = image.clone();
        addWeighted(_exposed, 0.0, image, alpha, 0.0, _exposed);
    } else {
        addWeighted(_exposed, 1.0, image, alpha, 0.0, _exposed);
    }
    _frameCount++;

If you also want to make the image brighter to some extent, you could simulate it via a multiplication factor: 如果您还想在某种程度上使图像更亮,您可以通过乘法因子来模拟它:

    if (_frameCount == 0) {
       _exposed = image.clone();
        addWeighted(_exposed, 0.0, image, alpha*brightfactor, 0.0, _exposed);
    } else {
        addWeighted(_exposed, 1.0, image, alpha*brightfactor, 0.0, _exposed);
    }
    _frameCount++;

Tune brightfactor to a value it best simulate a real increasing in exposure time. 将brightfactor调整为最能模拟曝光时间真实增加的值。 (EDIT: a value between 1.5 and 2.5 should do the job) (编辑:1.5到2.5之间的值应该完成工作)

In my opinion using alpha is not the correct way. 在我看来,使用alpha并不是正确的方法。

You should accumulate the (absolute) differences from the exposure frame: 你应该积累与曝光框架的(绝对)差异:

if (_frameCount == 0) {
   _exposed = image.clone();
} else {
   _exposed += image - _exposed;
}

Following approach should work in a case where 以下方法应适用于以下情况

  • you have a known (or learned) background 你有一个已知的(或学到的)背景
  • you can segment the motion so that you get a mask for the foreground 您可以对动作进行分段,以便为前景获取蒙版

Suppose you obtained such a background and can get a foreground mask for each frame that you capture after the background-learning stage. 假设您获得了这样的背景,并且可以为在背景学习阶段之后捕获的每个帧获取前景蒙版。 Let's denote 我们来表示

  • the learned background as bg 学习背景为bg
  • frame at time t as I_t 在时间t的帧为I_t
  • corresponding foreground mask for I_t as fgmask_t I_t的相应前景掩码为fgmask_t

Then update the background for each frame as 然后将每个帧的背景更新为

I_t.copyTo(bg, fgmask_t) I_t.copyTo(bg,fgmask_t)

where copyTo is a method of OpenCV Mat class. 其中copyTo是OpenCV Mat类的方法。

So the procedure would be 所以程序就是这样

Learn bg

for each frame I_t
{
    get fgmask_t
    I_t.copyTo(bg, fgmask_t)
}

When frame capture is over, bg will contain the history of motion. 当帧捕获结束时, bg将包含运动历史。

You can use a Gaussian Mixture Model ( BackgroundSubtractorMOG variants in OpenCV) or a simple frame differencing technique for this. 您可以使用高斯混合模型(OpenCV中的BackgroundSubtractorMOG变体)或简单的帧差分技术。 The quality will depend on how well the technique segments the motion (or the quality of the foreground mask). 质量将取决于该技术对运动(或前景蒙版的质量)进行分割的程度。

I think this should work well for a stationary camera, but if the camera moves, it may not work very well except in a situation where the camera tracks an object. 我认为这应该适用于固定式摄像机,但如果摄像机移动,除非在摄像机跟踪物体的情况下,它可能无法正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM