【问题标题】:Simulate long exposure from video frames OpenCV从视频帧 OpenCV 模拟长时间曝光
【发布时间】:2015-10-01 09:22:31
【问题描述】:

我正在尝试通过将图像(帧)组合成一张图像并通过基于预设 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");
        }
    }
}

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

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

【问题讨论】:

  • 您的代码中的问题是您仅对 1 帧进行 30 次平均。

标签: c++ ios objective-c opencv


【解决方案1】:

首先,(可能这不是您的情况,因为您指出您正在处理视频而不是相机)如果您的代码基于帧速率的值,请确保 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++;

将亮度因子调整为最能模拟曝光时间实际增加的值。 (编辑:1.5 和 2.5 之间的值应该可以完成这项工作)

【讨论】:

  • 太好了,我在文档中看到了这个功能,但没有尝试过,我会试试看。也感谢您提供额外的见解。
  • 我对您的回答有疑问,为什么第一行中的 alpha 为零?这不会使src1 图像完全清晰吗?与第二次通话的测试版相同的问题。谢谢!我也刚试了一下,效果还不错,你知道我可以让图像稍微清晰/降低帧之间的敏感度吗?
  • 第一行中的 alpha 等于 0 只是使用类似于第二行代码的技巧。它采用第一帧并将其乘以 1/30,这使得它更暗(_exposed 现在没有总结)。然后第二行将此暗图像添加到当前帧的 1/30。每次执行时,生成的图像 (_exposed) 都会变得更清晰。效果是平均 30 帧,就像从长时间曝光获得的一样。
  • 但是真正增加曝光的效果也是更亮的图像:您可以通过brightfactor参数模拟它。改变其值以找出最能模拟真实长时间曝光的值。从值 1.5 开始并增加它。
  • 我试过了,但没有发现曝光和原始成像仪有任何区别。
【解决方案2】:

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

你应该累积与曝光帧的(绝对)差异:

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

【讨论】:

  • 它不能很好地模拟静止图像的简单情况。在真实的相机中,生成的图像很亮,在您的代码中您将获得原始帧。
  • 它也不模拟模糊效果,问题是尼克希望暴露的效果接近现实多远
【解决方案3】:

以下方法应该适用于以下情况

  • 你有已知(或学过的)背景
  • 您可以对运动进行分段,以便获得前景蒙版

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

  • 作为bg的学习背景
  • 帧在时间 tI_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 变体)或简单的帧差分技术。质量将取决于技术对运动的分割程度(或前景蒙版的质量)。

我认为这应该适用于静止的相机,但如果相机移动,它可能不会很好地工作,除非在相机跟踪物体的情况下。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 2016-02-13
    • 2017-07-02
    • 2015-12-27
    • 2023-01-03
    • 2014-09-24
    • 1970-01-01
    相关资源
    最近更新 更多