2015-07-13 16 views
17

Sto tentando di simulare una foto a lunga esposizione combinando le immagini (fotogrammi) in un'immagine e eseguendo operazioni basate su un alfa preimpostato. Lo sto facendo su un iPhone e attualmente ho la lunghezza del video impostata su 1 secondo (30 fotogrammi). L'alpha è impostato su 1.0/frameCount, tuttavia ho codificato in modo rigido in 30 per rappresentare un secondo di 30 acquisizione video FPS. Fermo le operazioni una volta raggiunto un secondo di video/30 fotogrammi. L'idea è che l'utente può impostare un timer per x secondi e io farò i calcoli per capire quanti fotogrammi permettere.Simulare l'esposizione lunga dai fotogrammi video OpenCV

Ecco il codice che sto usando:

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

Quando eseguo questo codice Io fondamentalmente tornare un fermo immagine che sembra come se si tratta di un singolo fotogramma. Ecco un esempio:

enter image description here

Qualcuno sa come posso produrre l'effetto desiderato di un'immagine lunga esposizione da fotogrammi video dato che so quanti fotogrammi ci sarà?

+0

problema nel codice è che si sta facendo la media di solo 1 fotogrammi 30 volte. – Abc

risposta

14

Prima di tutto, (probabilmente questo non è il tuo caso, come hai sottolineato che stai lavorando su un video e non su una macchina fotografica) se basi il tuo codice sul valore della frequenza fotogrammi, assicurati che 30fps sia il valore effettivo e non il massimo. A volte le telecamere regolano automaticamente quel numero in base alla quantità di luce che ricevono dall'ambiente. Se è buio, aumenta il tempo di esposizione e quindi diminuisce il framerate.

Secondo punto, è davvero difficile simulare il vero meccanismo dell'esposizione fotografica dato un mucchio di pixel. Immagina di voler raddoppiare il tempo di esposizione, questo dovrebbe essere simulato da due fotogrammi consecutivi. Nel mondo reale raddoppiare il tempo di esposizione significa che la velocità dell'otturatore è dimezzata e quindi il doppio della luce colpisce il sensore o il film, il risultato è un'immagine più luminosa.
Come si simula questo? Considerare per semplicità il caso di due immagini in scala di grigi abbastanza luminose che si desidera unire. Se in un dato punto i valori dei pixel sono, ad esempio, 180 e 181 qual è il valore risultante? La prima risposta sarebbe 180 + 181, ma l'intensità dei pixel varia tra 0 e 255, quindi deve essere troncata a 255. La fotocamera reale con esposizione maggiore probabilmente si comporterebbe in modo diverso, non raggiungendo il valore massimo.

Ora prenderò in considerazione il codice.
La prima volta che si elabora un'immagine (ad esempio, si esegue la funzione), è sufficiente memorizzare la cornice in variabile _esposta.
La seconda volta che si fondono 29/30 del nuovo fotogramma e 1/30 dell'immagine precedentemente memorizzata.
La terza volta 29/30 del terzo fotogramma con il risultato dell'operazione precedente. Ciò si traduce in un peso di sbiadimento sul primo fotogramma che è praticamente scomparso.
L'ultima volta che si chiama la funzione, di nuovo, si sommano 29/30 dell'ultimo fotogramma e 1/30 del risultato precedente. A sua volta, ciò significa che l'effetto dei primi fotogrammi è praticamente scomparso e anche il precedente conta solo per una quota di 29/(30x30). L'immagine che si ottiene è solo l'ultimo fotogramma con una leggera sfocatura proveniente dai fotogrammi precedenti.
Come si ottiene una simulazione dell'esposizione? Se si vuole semplicemente media 30 fotogrammi si deve sostituire queste linee:

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++; 

Se vuoi anche per rendere l'immagine più luminosa in una certa misura, si potrebbe simulare tramite un fattore di moltiplicazione:

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++; 

Accordare il fattore luminoso a un valore che simula meglio un aumento reale del tempo di esposizione. (EDIT: un valore compreso tra 1,5 e 2,5 dovrebbe fare il lavoro)

+0

Grande, ho visto questa funzione nei documenti ma non avevo dato un colpo, lo proverò. Grazie per l'intuizione in più. – Clip

+0

Ho una domanda con la tua risposta, perché l'alfa nella prima riga è zero? Questo non renderà l'immagine 'src1' completamente chiara? Stessa domanda con la beta della seconda chiamata. Grazie! Inoltre ho appena provato e sembra funzionare abbastanza bene, sai comunque che posso rendere l'immagine leggermente più chiara/ridurre la sensibilità tra i frame? – Clip

+1

L'alfa uguale a zero nella prima riga è solo un trucco per utilizzare un codice simile a quello della seconda riga. Prende il primo frame e lo moltiplica per 1/30, il che lo rende molto più scuro (_exposed non è riassunto ora). Quindi la seconda riga aggiunge questa immagine scura a 1/30 del fotogramma corrente. Ogni volta che viene eseguita, l'immagine risultante (_exposed) diventa più chiara. L'effetto è una media di 30 fotogrammi, proprio come quello ottenuto da una lunga esposizione. –

3

Secondo me l'utilizzo di alfa non è il modo corretto.

Si dovrebbe accumulare le differenze (assoluti) dal telaio di esposizione:

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

Non simula bene la semplice situazione di un'immagine fissa. In una fotocamera reale l'immagine risultante è luminosa, nel tuo codice otterrai la cornice originale. –

+0

anche non simulare l'effetto sfocatura, la domanda è quanto Nick vuole che l'effetto esposto sia vicino alla realtà – meirm

1

Seguendo approccio dovrebbe funzionare in un caso in cui

  • voi hanno un noto (o imparato) sfondo
  • puoi segmentare il movimento in modo da ottenere una maschera per il primo piano

Supponiamo di aver ottenuto tale sfondo e di ottenere una maschera in primo piano per ciascun fotogramma acquisito dopo la fase di apprendimento in background. Denotiamo

  • sfondo imparato come bg
  • fotogramma alla volta t come I_t
  • relativa maschera di primo piano per I_t come fgmask_t

quindi aggiornare lo sfondo per ogni fotogramma come

I_t.copyTo (bg, fgmask_t)

dove copyTo è un metodo di classe OpenCV Mat.

Quindi la procedura sarebbe

Learn bg 

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

Quando cattura frame è finita, bg conterrà la storia del movimento.

È possibile utilizzare un modello di miscela gaussiana (varianti BackgroundSubtractorMOG in OpenCV) o una semplice tecnica di differenziazione del frame per questo. La qualità dipenderà da quanto bene la tecnica segmenta il movimento (o la qualità della maschera in primo piano).

Penso che questo dovrebbe funzionare bene per una telecamera fissa, ma se la telecamera si muove, potrebbe non funzionare molto bene tranne in una situazione in cui la telecamera tiene traccia di un oggetto.

Problemi correlati