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

时间:2015-07-13 07:41:17

标签: c++ ios objective-c opencv

我试图通过将图像(帧)组合成一个图像并通过基于预设的alpha执行操作来模拟长曝光照片。我在iPhone上这样做,我目前将视频长度设置为1秒(30帧)。 alpha设置为1.0/frameCount但我在30中硬编码表示30 FPS视频捕获的一秒。一旦达到一秒视频/ 30帧,我就停止操作。这个想法是用户可以设置一个x秒的计时器,我将进行数学计算以确定允许的帧数。

以下是我正在使用的代码:

- (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");
        }
    }
}

当我运行此代码时,我基本上会找回一个看起来好像是单帧的静止图像。这是一个例子:

enter image description here

有人知道如何从视频帧中产生长曝光图像所需的效果,因为我知道会有多少帧吗?

3 个答案:

答案 0 :(得分:14)

首先,(可能这不是你的情况,因为你指出你正在处理视频而不是相机)如果你的代码基于帧速率的值,请确保30fps是有效价值而非最大价值。有时,相机会根据从环境中获得的光量自动调整该数量。如果天黑,则曝光时间增加,因此帧速率降低。

第二点,给出一堆像素很难模拟照片曝光的真实机制。 想象一下,你想要将曝光时间加倍,这应该通过两个连续的帧来模拟。 在现实世界中,曝光时间加倍意味着快门速度减半,因此传感器或胶片的亮度会增加两倍,从而产生更亮的图像。
你怎么模拟这个?为简单起见,请考虑要合并的两个非常明亮的灰度图像。如果在给定点,像素值是180和181,那么结果值是多少?第一个答案是180 + 181,但像素强度范围在0到255之间,因此必须在255处截断。 曝光增加的真实相机可能表现不同,但未达到最大值。

现在我会考虑你的代码 第一次处理图像(即运行函数)时,只需将帧存储在变量_exposed中即可 第二次混合新帧的29/30和先前存储图像的1/30 第三帧的第三次29/30与前一次操作的结果。这导致第一帧上的褪色重量几乎消失 上次再次调用该函数时,您总结了最后一帧的29/30和前一个结果的1/30。反过来,这意味着第一帧的效果几乎消失,甚至前一帧的效果仅计入29 /(30x30)的份额。 您获得的图像只是前一帧中出现轻微模糊的最后一帧 你如何获得曝光模拟? 如果你只想平均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 (_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++;

将brightfactor调整为最能模拟曝光时间实际增加的值。 (编辑:1.5到2.5之间的值应该完成工作)

答案 1 :(得分:3)

在我看来,使用alpha并不是正确的方法。

您应该从曝光帧中累积(绝对)差异:

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

答案 2 :(得分:1)

以下方法适用于

的情况
  • 你有一个已知(或学到的)背景
  • 您可以对动作进行分段,以便获得前景蒙版

假设您获得了这样的背景,并且可以为在背景学习阶段之后捕获的每个帧获取前景蒙版。我们用来表示

  • 学习的背景为 bg
  • 时间 t 的框架 I_t
  • I_t 的相应前景蒙版 fgmask_t

然后将每个帧的背景更新为

I_t.copyTo(bg,fgmask_t)

其中 copyTo 是OpenCV Mat类的方法。

所以程序将是

Learn bg

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

当帧捕获结束时, bg 将包含动作历史。

您可以使用高斯混合模型(OpenCV中的 BackgroundSubtractorMOG 变体)或简单的帧差分技术。质量取决于技术对运动(或前景蒙版的质量)进行分割的程度。

我认为这应该适用于固定式相机,但如果相机移动,除非在相机跟踪物体的情况下,它可能无法正常工作。