C++ 从OpenCV视频帧模拟长时间曝光

C++ 从OpenCV视频帧模拟长时间曝光,c++,ios,objective-c,opencv,C++,Ios,Objective C,Opencv,我试图通过将图像(帧)组合成一幅图像并根据预设的alpha执行操作来模拟长曝光照片。我在iPhone上做这项工作,目前我将视频长度设置为1秒(30帧)。alpha设置为1.0/帧数,但我硬编码为30,表示每秒30帧的视频捕获。一旦达到1秒视频/30帧,我将停止操作。这个想法是用户可以设置一个x秒的计时器,我会计算出允许的帧数 以下是我正在使用的代码: - (void)processImage:(Mat&)image { if (_isRecording) {

我试图通过将图像(帧)组合成一幅图像并根据预设的alpha执行操作来模拟长曝光照片。我在iPhone上做这项工作,目前我将视频长度设置为1秒(30帧)。alpha设置为
1.0/帧数
,但我硬编码为30,表示每秒30帧的视频捕获。一旦达到1秒视频/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");
        }
    }
}
当我运行这段代码时,我基本上得到了一个静止图像,看起来就像是一个单帧。以下是一个例子:

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

首先,(可能这不是你的情况,正如你指出的,你是在处理视频而不是相机),如果你的代码基于帧速率的值,确保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之间的值就可以了)

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

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

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

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

  • 你有一个已知(或习得)的背景
  • 您可以分割运动,以便获得前景的遮罩
假设您获得了这样一个背景,并且可以为在背景学习阶段之后捕获的每个帧获得一个前景遮罩。让我们表示

  • 学习背景为bg
  • 在时间tasI\u t
  • I\u t的对应前景掩码为fgmask\u t
然后将每个帧的背景更新为

I\u t.copyTo(背景、背景)

其中,copyTo是OpenCV Mat类的一种方法

所以程序是

Learn bg

for each frame I_t
{
    get fgmask_t
    I_t.copyTo(bg, fgmask_t)
}
帧捕获结束后,bg将包含运动历史

您可以使用高斯混合模型(OpenCV中的BackgroundSubtractorMOG变体)或简单的帧差分技术来实现这一点。质量将取决于技术分割运动的程度(或前景遮罩的质量)


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

太好了,我在文档中看到了这个功能,但没有给它一个镜头,我会尝试一下。谢谢你的额外见解。我有一个问题和你的答案,为什么阿尔法在第一行是零?这不会使
src1
图像完全清晰吗?第二次通话的beta版也有同样的问题。谢谢另外,我刚刚试过,它似乎工作得相当好,你知道我可以让图像稍微清晰一点/降低帧间的灵敏度吗?第一行中的alpha等于零只是一个使用类似于第二行代码的技巧。它取第一帧并将其乘以1/30,这使它变得更暗(现在不求和)。然后第二行将此暗图像添加到当前帧的1/30。每次执行时,生成的图像(_exposed)都会变得更清晰。效果是平均30帧,就像长时间曝光获得的效果一样。但实际增加曝光的效果也是更亮的图像:可以通过brightfactor参数进行模拟。改变其值以找出最能模拟真实长时间曝光的值。从值1.5开始并增加它。我试过了,但我没有看到曝光和原始ima有任何区别