Ho una sequenza di immagini per cui voglio calcolare l'immagine mediana (come rimuovere elementi in movimento). Intuitivamente, l'hard-coding di un loop per passare attraverso tutti i pixel avrebbe un tempo di esecuzione lordo e un utilizzo della memoria abbastanza grande. C'è un modo per farlo facilmente in OpenCV? (Non sono interessato a fare la media, ho bisogno di fare una mediana). Sto scrivendo questo per Android (usando OpenCV4Android), quindi ovviamente la potenza di calcolo è limitata.Ottenere un'immagine mediana dalla sequenza di immagini con OpenCV
risposta
Se la media è ok:
Mat result(CV_64FC3, listImages[0].size());
for(int i = 0; i < listImages.size(); i++) {
result += listImages[i];
}
result /= listImages.size();
result.convertTo(result, CV_8UC3);
EDIT:
Questo rapido pseudo-mediana dovrebbe fare il trucco:
// Following algorithm will retain the pixel which is the closest to the mean
// Computing Mean
Mat tmpResult = Mat.zeros(listImages[0].size(), CV_64FC3);
for(int i = 0; i < listImages.size(); i++) {
tmpResult += listImages[i];
}
tmpResult /= listImages.size();
tmpResult.convertTo(tmpResult, CV_8UC3);
// We will now, for each pixel retain the closest to the mean
// Initializing result with the first image
Mat result(listImages[0].clone());
Mat diff1, diff2, minDiff;
for(int i = 1; i < listImages.size(); i++) {
// Computing diff between mean/newImage and mean/lastResult
absdiff(tmpResult, listImages[i], diff1);
absdiff(tmpResult, result, diff2);
// If a pixel of the new image is closer to the mean, it replaces the old one
min(diff1, diff2, minDiff);
// Get the old pixels that are still ok
result = result & ~(minDiff - diff2);
// Get the new pixels
result += listImages[i] & (minDiff - diff2);
}
Tuttavia quella classica dovrebbe essere anche abbastanza veloce. È O (nb^2 * w * h) dove nb è il numero di immagini e w, h la loro larghezza, altezza. Quanto sopra è O (nb * w * h) con più operazioni su Mats.
Il codice per quello classico (quasi tutti i calcoli saranno effettuati in nativo):
Mat tmp;
// We will sorting pixels where the first mat will get the lowest pixels and the last one, the highest
for(int i = 0; i < listImages.size(); i++) {
for(int j = i + 1; j < listImages.size(); j++) {
listImages[i].copyTo(tmp);
min(listImages[i], listImages[j], listImages[i]);
max(listImages[j], tmp, listImages[j]);
}
}
// We get the median
Mat result = listImages[listImages.size()/2];
OP dice "Non sono interessato a fare la media". – Antonio
Non l'ho visto:/Ma il codice per calcolare la mediana sarà molto più complesso e dato che i risultati medi e medi sono chiusi ho suggerito di considerare il mezzo ... –
Ok, aggiornato con due algos mediani. –
Per quanto ne so, non vi alcuna funzione OpenCV che crea un'immagine mediano dalla sequenza di immagini. Avevo bisogno della stessa funzionalità un paio di anni fa e ho dovuto implementarlo da solo. È relativamente lento perché per ogni pixel è necessario estrarre i pixel pertinenti da più immagini (accesso inefficiente alla memoria) e calcolare la mediana (anche un processo che richiede tempo).
possibili modi per aumentare l'efficienza sono:
- Non c'è bisogno di calcolare mediana da tutte le immagini. Un piccolo sottoinsieme di immagini sarà sufficiente.
- È possibile trovare algoritmi più efficienti per trovare la mediana di alcuni piccoli gruppi. Ad esempio, ho usato un algoritmo che può trovare in modo efficiente la mediana in un gruppo di nove valori.
google per mediana efficiente – Micka
Questo è un problema interessante, ma sembra troppo impegnativo per il tipo di hardware che si menziona (senza contare che in generale Java è più lento di C++). Quante immagini vuoi coinvolgere nella mediana? Qual è la risoluzione delle immagini? A proposito, hai già verificato se il calcolo di un filtro mediano all'interno di ogni singolo fotogramma non fornisse già dati sufficienti? – Antonio
Nessun feedback? Ho alcune idee ma dovresti fornire maggiori informazioni (vedi le mie domande sopra) – Antonio