bash-Script zum Mitteln von Videos

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Yadgar
Beiträge: 954
Registriert: 22.11.2010 22:11:08
Wohnort: Qal'a-ye Nil, Bergisch-Afghanistan (linksrheinische Exklave)
Kontaktdaten:

bash-Script zum Mitteln von Videos

Beitrag von Yadgar » 19.03.2018 16:41:56

Hi(gh)!

Da die Funktion -average von ImageMagick bei größeren Bildformaten und/oder Anzahlen zu mittelnder Bilder schnell an Speichergrenzen stößt (auf meinem 16 MiB-Boliden (hüstel!) geht 1280 x 720 x 1500 noch gut, bei 1280 x 720 x 5000 wird es dagegen unzumutbar langsam bzw. - ich habe es nicht bis zum Ende laufen lassen - es sieht so aus, als hinge sich ImageMagick auf, was bei 1280 x 720 x 25000 dann definitiv passiert) habe ich ein Skript geschrieben, das lange, z. B. aus Videos mit ffmpeg extrahierte Einzelbildfolgen in gleich große, für -average bequem handhabbare Tranchen aufteilt, diese dann jeweils mittelt und die so erzeugten Bilder wiederum mittelt, so dass am Ende für die ganze Bildfolge ein gemitteltes Bild steht. Dazu darf die Gesamtzahl der Bilder natürlich keine Primzahl sein und es muss der größte ganzzahlige Teiler beim Aufteilen der Tranchen verwendet werden... hier der Code:

Code: Alles auswählen

digits()
{
  c=1
  d=0
  while [ "$c" -le "$1" ]
  do
    c=$((c*10))
    d=$((d+1))
  done
  return $d
}

#function leadingzeroes()
leadingzeroes()
{
  lz=""
  for i in $(seq 0 $1)
  do
    lz=${lz}0
  done
  echo $lz
  return $lz
}

d="/home/Video/mudcompilation/pre/"
series=mud007
cd $d

filenum_original=$(find $workdir -type f | wc -l)
filenum=$filenum_original
prim=(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541)
i=0
l=0
primefacs=()
while [ $((prim[$i]*prim[$i])) -le $filenum ] 
do
  if [ $((filenum%prim[$i])) -eq 0 ]
  then
    primefacs+=(${prim[$i]})
    filenum=$((filenum/prim[$i]))
    l=$((l+1))
  else
    i=$((i+1))
  fi
done

#echo "Primfaktoren von "${filenum_original}": "
a=1
for i in $(seq 0 $((l-1)))
do
  #echo ${primefacs[$i]}
  a=$((a*${primefacs[$i]}))
done

echo $a

if [ $i -gt 100 ]
then
  echo "Die Bildsequenz kann leider nicht in gleich große Tranchen aufgeteilt werden!"
else
  mkdir avgs
  fac=$a
  tra=$((filenum_original/fac))
  digits $fac
  facdigits=$?
  for i in $(seq 1 $fac)
  do
    subd=${series}"_"${i}
    mkdir $subd
    echo "Verzeichnis "$subd" wird erzeugt!"
    digits $i
    idigits=$?
    start=$(((i-1)*tra+1))
    end=$((tra*i))
    for j in $(seq $start $end)
    do  
      digits $j
      jdigits=$?
      echo $jdigits
      zeroes=`leadingzeroes $((5-jdigits-1))`
      fn=${series}"-"${zeroes}${j}".png"
      cp $fn $subd
      echo "Datei "${fn}" wurde nach "${subd}" kopiert!"
    done
    cd $subd
    zeroes2=`leadingzeroes $((facdigits-idigits-1))`
    convert -average * "../avgs/${series}-"${zeroes2}${i}".png"
    echo "Frames der Tranche "${i}" wurden gemittelt."
    cd ..
  done
  cd avgs
  convert -average * ../../avgtests/avgtest_010.png
  echo "Gemittelte Tranchen-Frames wurden wiederum gemittelt."
  cd ..
fi 
Um Rechenzeit zu sparen, habe ich die 100 ersten Primzahlen in einem vordefinierten Array gespeichert, errechnet wurden sie mit einem kleinen C++-Programm:

Code: Alles auswählen

#include <iostream>
using namespace std;

int main()
{
  unsigned short n=100, i=1, c=2, j;

  while (i <= n)
  {
    j = 1;
    while (j*j <= c)
    {
      if (j != 1 && c%j == 0) break;
      j++;
    }
    if (j*j > c)
    {
      cout << c << endl;
      i++;
    }
    c++;
  }

  return 0;
}
Da bei der Primfaktorzerlegung nur bis zur höchsten Primzahl, die noch kleiner ist als die Quadratwurzel der zu untersuchenden Zahl gesucht werden muss, reichen die Primzahlen im Array für die allermeisten Videos (bei 25 fps) aus... sollte ich demnächst Lust bekommen, die 7 Stunden 14 Minuten "Bergensbanen minutt for minutt" zu mitteln, werde ich wohl noch 20 oder 25 Primzahlen hinzufügen...
If operating systems were countries, Linux would be pre-1978 Afghanistan: an all-time favourite among alternative globetrotters, but shunned by mainstream tourists because of its lack of fancy beaches, shortage of alcoholic beverages and its fondness of beards...

Benutzeravatar
Yadgar
Beiträge: 954
Registriert: 22.11.2010 22:11:08
Wohnort: Qal'a-ye Nil, Bergisch-Afghanistan (linksrheinische Exklave)
Kontaktdaten:

Re: bash-Script zum Mitteln von Videos

Beitrag von Yadgar » 25.03.2018 05:35:26

Hi(gh)!

Eine verbesserte Version meines Videomittelungs-Scripts:

Code: Alles auswählen

#function digits()
digits()
{
  c=1
  d=0
  while [ "$c" -le "$1" ]
  do
    c=$((c*10))
    d=$((d+1))
  done
  return $d
}

#function leadingzeroes()
leadingzeroes()
{
  lz=""
  for i in $(seq 0 $1)
  do
    lz=${lz}0
  done
  echo $lz
  return $lz
}

d="/home/Video/mudcompilation/pre/"
series=mud026
limit=2281
cd $d

filenum_original=$(find $workdir -type f | wc -l)
filenum=$filenum_original
prim=(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541)
i=0
l=0
primefacs=()
while [ $((prim[$i]*prim[$i])) -le $filenum ] 
do
  if [ $((filenum%prim[$i])) -eq 0 ]
  then
    primefacs+=(${prim[$i]})
    filenum=$((filenum/prim[$i]))
    l=$((l+1))
  else
    i=$((i+1))
  fi
done

#echo "Primfaktoren von "${filenum_original}": "
a=1
for i in $(seq 0 $((l-1)))
do
  #echo ${primefacs[$i]}
  a=$((a*${primefacs[$i]}))
done

echo $a
b=$((filenum_original/a))

if [ $l -eq 0 -o $a -ge $limit -o $b -ge $limit ]
then
  echo "Die Länge der Bildsequenz ist entweder eine Primzahl oder läßt sich nur so teilen, dass entweder "${limit}" oder mehr Tranchen entstehen oder jede Tranche "${limit}" oder mehr Einzelbilder enthält. In den letzten beiden genannten Fällen ist der Computer mit der Mittelung der Einzelbilder überfordert; falls die Länge der Sequenz eine Primzahl, aber kürzer als "${limit}" ist, kann -average * zielbild.png von Hand eingegeben werden."
else
  mkdir avgs

  
  if [ $b -le $limit ]
  then
    tra=$b
    fac=$a
  else
    tra=$a
    fac=$b
  fi
  digits $fac
  facdigits=$?
  for i in $(seq 1 $fac)
  do
    subd=${series}"_"${i}
    mkdir $subd
    echo "Verzeichnis "$subd" wird erzeugt!"
    digits $i
    idigits=$?
    start=$(((i-1)*tra+1))
    end=$((tra*i))
    for j in $(seq $start $end)
    do  
      digits $j
      jdigits=$?
      echo $jdigits
      zeroes=`leadingzeroes $((5-jdigits-1))`
      fn=${series}"-"${zeroes}${j}".png"
      cp $fn $subd
      echo "Datei "${fn}" wurde nach "${subd}" kopiert!"
    done
    cd $subd
    zeroes2=`leadingzeroes $((facdigits-idigits-1))`
    echo "Frames der Tranche "${i}" werden gemittelt:"
    convert -average * "../avgs/${series}-"${zeroes2}${i}".png"
    cd ..
  done
  cd avgs
  echo "Gemittelte Tranchen-Frames werden wiederum gemittelt:"
  convert -average * ../../avgtests/avgtest_030.png
  cd ..
fi 
Die Bedingung für den Programmabbruch wurde geändert: die Mittelung wird jetzt nicht ausgeführt, wenn die Gesamtzahl der Frames eine Primzahl (l = 0) oder einer der beiden sich durch den höchsten ganzzahligen Teiler ergebenden Faktoren größer als 2281 ist. Der Wert 2281 stellt einfach die größte Tranchenlänge in einer Serie von etwa 30 Videos dar, bei der die Mittelung noch ohne Aufhängen oder Absturz gelang - in Zukunft kann er durchaus auch noch höher liegen.
If operating systems were countries, Linux would be pre-1978 Afghanistan: an all-time favourite among alternative globetrotters, but shunned by mainstream tourists because of its lack of fancy beaches, shortage of alcoholic beverages and its fondness of beards...

NAB
Beiträge: 5501
Registriert: 06.03.2011 16:02:23
Lizenz eigener Beiträge: MIT Lizenz

Re: bash-Script zum Mitteln von Videos

Beitrag von NAB » 25.03.2018 06:54:49

Darf ich mal ganz blöd fragen ... warum macht man das? Wozu braucht man das? Wofür braucht man ein gemitteltes Bild über einen gesamten Film?
(Dein Script ist übrigens so ganz ohne Kommentare etwas schwer verdaulich)
Never change a broken system. It could be worse afterwards.

"No computer system can be absolutely secure." Intel Document Number: 336983-001

Benutzeravatar
Yadgar
Beiträge: 954
Registriert: 22.11.2010 22:11:08
Wohnort: Qal'a-ye Nil, Bergisch-Afghanistan (linksrheinische Exklave)
Kontaktdaten:

Re: bash-Script zum Mitteln von Videos

Beitrag von Yadgar » 25.03.2018 23:32:09

NAB hat geschrieben: ↑ zum Beitrag ↑
25.03.2018 06:54:49
Darf ich mal ganz blöd fragen ... warum macht man das? Wozu braucht man das? Wofür braucht man ein gemitteltes Bild über einen gesamten Film?
L'art pour l'art... wobei ich zugeben, dass Mittelungen über einen ganzen Film hinweg keinen allzugroßen Nutzen haben... aber wenn ich z. B. iterativ mittele, also z. B. von fortlaufenden Frames aus immer die jeweils nächsten z. B. 10000 Frames, lassen sich je nach Ausgangsmaterial traumähnliche, psychedelische Sequenzen erzeugen...

Einen Film von abendfüllender Länge habe ich noch nicht gemittelt... wäre ja wirklich mal interessant, wie der Durchschnitt aller Bilder etwa von "Zurück in die Zukunft" aussieht!
If operating systems were countries, Linux would be pre-1978 Afghanistan: an all-time favourite among alternative globetrotters, but shunned by mainstream tourists because of its lack of fancy beaches, shortage of alcoholic beverages and its fondness of beards...

NAB
Beiträge: 5501
Registriert: 06.03.2011 16:02:23
Lizenz eigener Beiträge: MIT Lizenz

Re: bash-Script zum Mitteln von Videos

Beitrag von NAB » 26.03.2018 01:51:43

Yadgar hat geschrieben: ↑ zum Beitrag ↑
25.03.2018 23:32:09
wenn ich z. B. iterativ mittele, also z. B. von fortlaufenden Frames aus immer die jeweils nächsten z. B. 10000 Frames, lassen sich je nach Ausgangsmaterial traumähnliche, psychedelische Sequenzen erzeugen...
Ja, das kann ich mir vorstellen ... das sieht vermutlich so ähnlich aus wie wenn man den zeitlichen Rauschfilter viel zu stark einstellt ... die Bilder fließen und wabern ineinander :mrgreen:
Aber
Yadgar hat geschrieben: ↑ zum Beitrag ↑
25.03.2018 23:32:09
Einen Film von abendfüllender Länge habe ich noch nicht gemittelt... wäre ja wirklich mal interessant, wie der Durchschnitt aller Bilder etwa von "Zurück in die Zukunft" aussieht!
dabei würd ich erwarten, dass einfach nur ein mehr oder weniger fleckiges Graubild herauskommt. Aber gut, lassen wir das mal als Kunst durchgehen :wink:
Never change a broken system. It could be worse afterwards.

"No computer system can be absolutely secure." Intel Document Number: 336983-001

Antworten