Подтвердить что ты не робот

Имитировать длительную экспозицию от видеокадров OpenCV

Я пытаюсь имитировать фотографию с длительным выдержкой, комбинируя изображения (кадры) в одно изображение и выполняя операции на основе предустановленной альфы. Я делаю это на iPhone, и в настоящее время у меня есть длина видео, установленная на 1 секунду (30 кадров). Альфа устанавливается на 1.0/frameCount, однако я жестко закодирован в 30, чтобы представить одну секунду из 30 FPS видеозахвата. Я останавливаю операции, когда достигнет одной секунды видео /30 кадров. Идея заключается в том, что пользователь может установить таймер на х секунд, и я сделаю математику, чтобы выяснить, сколько кадров разрешено.

Вот код, который я использую:

- (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

Кто-нибудь знает, как я могу произвести желаемый эффект изображения с длительным выдержкой из видеокадров, учитывая, что я знаю, сколько кадров будет?

4b9b3361

Ответ 1

Прежде всего (возможно, это не ваш случай, поскольку вы указали, что работаете над видео, а не с камерой), если вы основываете свой код на значении частоты кадров, убедитесь, что 30 кадров в секунду эффективная стоимость, а не максимальная. Иногда камеры автоматически корректируют это число в зависимости от количества света, которое они получают от окружающей среды. Если он темный, время экспозиции увеличивается, и поэтому частота кадров уменьшается.

Во-вторых, очень сложно смоделировать реальный механизм экспозиции фотографий, учитывая кучу пикселей. Представьте, что вы хотите удвоить время экспозиции, это должно быть смоделировано двумя последовательными кадрами. В реальном мире удвоение времени экспозиции означает, что скорость затвора уменьшена вдвое, и в два раза больше света попадает на датчик или пленку, в результате получается более яркое изображение.
Как вы имитируете это? Рассмотрим для простоты случай двух довольно ярких изображений в оттенках серого, которые вы хотите объединить. Если в заданной точке значения пикселей, скажем, 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++;

Настройте ярлык на значение, которое лучше всего имитирует реальное увеличение времени экспозиции. (EDIT: значение от 1,5 до 2,5 должно выполняться)

Ответ 2

По-моему, использование альфы не является правильным способом.

Вы должны аккумулировать (абсолютные) отличия от кадра экспозиции:

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

Ответ 3

Следующий подход должен работать в случае, когда

  • у вас есть известный (или узнанный) фон
  • вы можете сегментировать движение, чтобы получить маску для переднего плана

Предположим, что вы получили такой фон и можете получить переднюю маску для каждого кадра, который вы захватываете после этапа фонового обучения. Обозначим через

  • изученный фон 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 будет содержать историю движения.

Для этого вы можете использовать Гауссовую модель смеси (варианты BackgroundSubtractorMOG в OpenCV) или простой метод разложения кадров. Качество будет зависеть от того, насколько хорошо метод сегментирует движение (или качество маски переднего плана).

Я думаю, что это должно хорошо работать для стационарной камеры, но если камера движется, она может работать не очень хорошо, за исключением ситуации, когда камера отслеживает объект.