2015-07-13 2 views
17

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

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

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

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

+0

Проблема в коде заключается в том, что вы усредняете только 1 кадр 30 раз. – Abc

ответ

14

Прежде всего, (возможно, это не ваш случай, поскольку вы указали, что работаете с видео, а не с камерой), если вы основываете свой код на значении частоты кадров, убедитесь, что 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 должно выполняться)

+0

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

+0

У меня вопрос с вашим ответом, почему альфа в первой строке нуля? Разве это не сделает изображение src1 полностью понятным? Тот же вопрос с бета второго вызова. Благодаря! Кроме того, я просто попробовал это и, похоже, работает достаточно хорошо, знаете ли вы, что я мог бы сделать изображение немного более четким/понижающим чувствительность между кадрами? – Clip

+1

Альфа, равный нулю в первой строке, является всего лишь трюком для использования кода, аналогичного ко второму. Он берет первый кадр и умножает его на 1/30, что делает его намного темнее (_exposed не суммируется сейчас). Затем вторая строка добавляет это темное изображение к 1/30 текущего кадра. Каждый раз, когда он выполняется, результирующее изображение (_exposed) становится более четким. Эффект - это усреднение 30 кадров, как и одно, полученное при длительной экспозиции. –

3

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

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

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

Он не очень хорошо имитирует простую ситуацию неподвижного изображения. В реальной камере результирующее изображение яркое, в вашем коде вы получите исходный кадр. –

+0

он также не имитирует эффект размытия, вопрос в том, насколько далеко Ник хочет, чтобы экспонированный эффект был близок к реальности – meirm

1

После подхода должен работать в случае, когда

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

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

  • ученого фон как Б.Г.
  • кадра во время т в 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) или простой метод разностной рамы для этого. Качество будет зависеть от того, насколько хорошо техника сегментирует движение (или качество маски переднего плана).

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

Смежные вопросы