Obsah
1. Použití knihovny MoviePy při úpravách a filtraci videa
2. Princip činnosti MoviePy při zpracování existujícího videa
3. Načtení videa a jeho následné uložení do odlišného formátu
4. Specifikace bitové rychlosti výsledného videa
5. Změna rychlosti vytvářeného videa
6. Střih videa (výběr snímků na časové ose)
7. Filtry aplikované na jednotlivé snímky
8. Změna rozlišení výsledného videa
10. Nastavení okrajů okolo videa
11. Aplikace masky na všechny snímky videa
12. Jednoduchý filtr pro inverzi všech snímků
13. Rozmazání videa v čase (motion blur)
14. Rozmazání s využitím vzdálenějších snímků
15. Jednoduchá kompozice typu „obraz v obraze“
16. Vytvoření jednoduché pipeline s uložením výsledku ve formě matice čtyř videoklipů
17. Vytvoření videa z jednotlivých snímků získaných z rastrových obrázků
18. Repositáře s demonstračními příklady a vygenerovanými videi
1. Použití knihovny MoviePy při úpravách a filtraci videa
Na předchozí tři části [1] [2] [3] krátkého seriálu o užitečné knihovně MoviePy dnes navážeme. Řekneme si totiž, jakými různými způsoby je možné upravovat již existující videa. S videi lze provádět různé „lineární“ editační operace, například převody do odlišného formátu (s použitím jiného kodeku), modifikaci bitové rychlosti, změnu rozměrů snímků (tím pádem i rozlišení výsledného videa), aplikaci různých filtrů na snímky, aplikaci mezisnímkových filtrů (motion blur), použití masky apod. Kromě toho jsou však podporovány i různé operace nelineární, zejména pak kombinace několika videí (spojení, proložení snímků, obraz v obrazu) apod.
V závěrečné části dnešního článku si ukážeme, jakým způsobem je možné v případě potřeby vytvořit video obsahující jednoduchou animovanou vizualizaci. Pro jednoduchost se bude jednat o mapu, na které jsou v grafické podobě zvýrazněny naměřené veličiny (v našem konkrétním případě se bude jednat o naměřenou a interpolovanou půdní vlhkost, která je dnes poměrně ostře sledována). V tomto případě se tedy knihovna MoviePy použije až v závěrečné fázi celého zpracování dat – od jejich měření, přes interpretaci (vizualizace na mapě) až po výslednou animaci, která zvýrazní změnu v čase. Ovšem díky tomu, že jsou jednotlivé snímky, ze kterých se výsledné video složí, tvořeny poli (přesněji řečeno datovými strukturami typu ndarray), lze i v závěrečné fázi do map různým způsobem zasahovat a provádět v nich různé více či méně zásadní modifikace.
Pro testy filtrace videa bude použita následující volně dostupné odpočítávání získané ze starého filmu:
https://tisnik.github.io/moviepy-videos/videoprocessing_input_video.htm
2. Princip činnosti MoviePy při zpracování existujícího videa
Nejprve se budeme věnovat lineární a nelineární editaci existujícího videa, tj. souborů obsahujících video zakódované nějakým podporovaným kodekem uloženým do zvoleného kontejneru (příkladem bude kombinace Ogg/Theora). Knihovna MoviePy v tomto případě pracuje přibližně následujícím způsobem:
- Vstupní soubor je postupně zpracováván známým externím nástrojem pojmenovaným ffmpeg. Výstupem je postupně vytvářená sekvence jednotlivých snímků popř. i audiostopy (ovšem dnes se budeme zabývat pouze zpracováním jednotlivých snímků, i když vstupní video obsahuje i zvukovou stopu).
- Jednotlivé snímky jsou v operační paměti počítače reprezentovány datovou strukturou typu ndarray z knihovny Numpy. Díky tomu je možné se snímky pracovat na nejnižší úrovni modifikací jednotlivých pixelů.
- Na snímky nebo na jejich sekvenci lze v případě potřeby aplikovat různé filtry, které si popíšeme v dalších kapitolách.
- Snímky se na výstupu opět spojují do sekvence, ze které se zvoleným kodekem generuje výsledný soubor s videem. Pro tuto činnost se opět volá externí nástroj ffmpeg.
Ve skutečnosti však může být situace nepatrně složitější, protože současně je možné zpracovávat větší množství videí na vstupu – tato videa lze kombinovat, spojovat, vytvořit snímky ve snímku atd. I s touto zajímavou a užitečnou problematikou se setkáme v navazujících kapitolách.
Příkladem může být použití třídy CompositeVideoClips zajišťující kompozici více vstupních videí:
- Vstupní soubory jsou postupně zpracovávány externím nástrojemffmpeg, podobně jako v případě, kdy je vstupem jediné video. Výstupem je tolik sekvencí jednotlivých snímků, kolik souborů se zpracovává.
- Na snímky nebo na jejich sekvenci lze aplikovat různé filtry, z nichž některé si popíšeme v dalších kapitolách.
- Snímky z jednotlivých sekvencí jsou zkombinovány dohromady. Při této činnosti se typicky používají různé masky (bitové mapy popř. pole s hodnotami od 0.0 do 1.0). Výsledkem kombinace je jediná sekvence výsledných snímků.
- Snímky se na výstupu opět spojují do sekvence, ze které se zvoleným kodekem generuje výsledný soubor s videem. Pro tuto činnost se opět volá externí nástroj ffmpeg (tento krok se nijak neliší od zpracování jediného videa).
3. Načtení videa a jeho následné uložení do odlišného formátu
První příklad, který si v dnešním článku ukážeme, bude velmi jednoduchý. Popíšeme si v něm základní použití třídy VideoFileClip, která reprezentuje video načítané z externího souboru a dekódované do operační paměti paměti ve formě jednotlivých snímků. V konstruktoru této třídy je nutné specifikovat jméno souboru s videem a popř. i další nepovinné parametry, zejména pak:
Parametr | Význam |
---|---|
has_mask | určuje, zda se video načte i s maskou (většinou ovšem není maska specifikována, typicky se jedná o specilitu MoviePy) |
audio | povolení či zákaz importu zvukových stop (samozřejmě pokud existují) |
resize_algorithm | specifikace algoritmu použitého při převzorkování snímků (volba mezi větší kvalitou nebo rychlostí převodu a výslednou velikostí videa) |
fps_source | volba, která metadata obsahují informaci o počtu snímků za sekundu |
Třída VideoFileClip obsahuje mj. i metodu pojmenovanou write_videofile(), která slouží pro export videa do zvoleného souboru s využitím kodeku a kontejneru, který je buď přesně specifikovaný, nebo si ho knihovna sama dokáže odvodit z koncovky. V našem případě bude postačovat odvození z koncovky, protože „.ogg“ je jednoznačně mapováno na kontejner/kodek Ogg/Theora. Příklad tedy provede dvě činnosti – načte video ve formátu MPEG-4 a uloží ho do formátu Ogg/Theora (samozřejmě je nutné uvažovat nad ztrátou kvality, která dekódovací-kódovací proces provází!):
from moviepy.editor import VideoFileClip # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # uložení video klipu do jiného souboru ve formátu Ogg/Theora clip.write_videofile('01_output_normal.ogv')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing01_convert_mp4_to_ogv.htm
4. Specifikace bitové rychlosti výsledného videa
Při exportu videa do nového souboru se zvoleným kontejnerem a kodekem je možné specifikovat i mezní bitovou rychlost (bitrate), která samozřejmě ovlivňuje jak kvalitu výsledného videa, tak i jeho celkovou velikost a požadavky na rychlost síťového připojení v případě, že video bude umístěno například na Youtube. Čím nižší bude specifikovaná hodnota bitrate, tím horší bude kvalita výsledného videa a naopak (i když vztah bitová rychlost:kvalita není lineární). Podívejme se na příklad, v němž zvýšíme bitovou rychlost na cca 700000 bitů za sekundu (bps), což je více než implicitní hodnota (proto bylo předchozí video tak nekvalitní):
from moviepy.editor import VideoFileClip # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # uložení video klipu do jiného souboru ve formátu Ogg/Theora clip.write_videofile('02_output_better_bitrate.ogv', bitrate='700000')
Poznámka: kvalita výsledného videa je samozřejmě omezena kvalitou videa vstupního, neboli jak říkají (nejenom) lidé z IT: „garbage in, garbage out“.
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing02_convert_change_bitrate.htm
5. Změna rychlosti vytvářeného videa
V některých případech je nutné video zpomalit nebo naopak zrychlit. Zde se již dostáváme k jednomu z filtrů, které jsou v knihovně MoviePy uživatelům-programátorům nabízeny. Tento filtr se jmenuje speedx a lze ho volat jako metodu objektu třídy VideoFileClip, které se předá reálné číslo představující zrychlení (pokud > 1) nebo naopak zpomalení (v případě, že < 1). Výsledkem tohoto filtru bude nové video (obecně třída VideoClip), se kterým je možné provádět naprosto stejné operace jako s jakýmkoli jiným videem.
from moviepy.editor import VideoFileClip # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # novy objekt reprezentující zrychleny video klip faster_clip = clip.speedx(1.5) # uložení video klipu do jiného souboru ve formátu Ogg/Theora faster_clip.write_videofile('03_output_faster_clip.ogv', bitrate='700000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing03_convert_speedup.htm
6. Střih videa (výběr snímků na časové ose)
Poměrně často se setkáme s požadavkem, aby výsledné video obsahovalo pouze některé sekvence z videa původního (například se odstraňují titulky atd.). I tento požadavek samozřejmě knihovna MoviePy dokáže splnit, a to konkrétně díky existenci filtru nazvaného subclip, kterému se předá čas prvního a posledního snímku z požadované sekvence. Výsledkem této operace je nové video, takže je snadné si postupně vytvořit libovolné množství takových sekvencí a ty posléze spojit do výsledného videa (popř. mezi ně vložit další efekty nebo jiná videa). Opět se podívejme na úplný kód tohoto jednoduchého příkladu:
from moviepy.editor import VideoFileClip # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # novy objekt reprezentujici video klip od 5 do 10 sekundy sub_clip = clip.subclip(5.0, 10.0) # uložení video klipu do jiného souboru ve formátu Ogg/Theora sub_clip.write_videofile('04_output_subclip.ogv', bitrate='700000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing04_use_subclip.htm
7. Filtry aplikované na jednotlivé snímky
V následujících pěti kapitolách si ukážeme příklady použití některých filtrů, které jsou postupně aplikovány na jednotlivé snímky. Do této skupiny patří především klasické filtry určené pro úpravu rastrových obrazů, změnu velikosti (zmenšení, zvětšení) snímků, aplikaci masky, přidání okrajů ke snímkům (což může být poměrně užitečné, jak uvidíme dále), otočení snímků apod. Speciálním případem je pak filtr typu motion blur, který dokáže vypočítat průměr z několika snímků zdrojového videa. Tento filtr použijeme k vytvoření dvou efektů popsaných v kapitole 13 a 14.
Poznámka: jednotlivé filtry, které budou postupně popsány v navazujících kapitolách, jsou většinou velmi jednoduché, takže je na místě otázka, k čemu se vlastně hodí. Síla (nejenom) těchto filtrů spočívá především v tom, že je lze různými způsoby kombinovat v „pipeline“ a dosáhnout tak mnohem složitějších efektů (typicky při použití masky).
8. Změna rozlišení výsledného videa
Dalším filtrem, který se ovšem bude volat poněkud odlišným způsobem, je filtr určený pro změnu rozlišení jednotlivých snímků a tím pádem i pro změnu rozlišení celého videa. Příslušný filtr se jmenuje resize a předává se mu relativní změna velikosti (1.5 odpovídá 150%, 0.25 pak 1/4). Tento filtr se volá přes univerzální metodu VideoClip.fx(), které se předá jak funkce realizující filtr, tak i její parametry. Výsledkem je opět nový video klip, podobně jako ve všech předchozích případech.
Zvětšení videa na 150 %:
from moviepy.editor import VideoFileClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # novy klip predstavujici video zvetsene na 150% puvodni velikosti resized_clip = clip.fx(resize, 1.50) # uložení video klipu do jiného souboru ve formátu Ogg/Theora resized_clip.write_videofile('05_output_larger.ogv', bitrate='700000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing05_resize_to_larger.htm
Zmenšení videa na pouhou jednu čtvrtinu původní velikosti:
from moviepy.editor import VideoFileClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # novy klip predstavujici video zmensene na 1/4 puvodni velikosti resized_clip = clip.fx(resize, 0.25) # uložení video klipu do jiného souboru ve formátu Ogg/Theora resized_clip.write_videofile('06_output_smaller.ogv', bitrate='700000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing06_resize_to_smaller.htm
9. Modifikace kontrastu
Další jednoduchý filtr, který je aplikovaný postupně na všechny pixely ve snímcích, se sice jmenuje colorx, ovšem ve skutečnosti slouží k velmi jednoduše pojaté změně kontrastu (bez barevného vyvážení a dalších pokročilejších technik). Filtr pracuje následujícím způsobem – každou barvovou složku pixelu vynásobí předanou konstantou. Pokud je konstanta menší než 1, dojde ke snížení kontrastu (a ztmavení snímku), jinak naopak ke zvýšení kontrastu a současně i k posunu celého barevného spektra:
def colorx(clip, factor): """ multiplies the clip's colors by the given factor, can be used to decrease or increase the clip's brightness (is that the reight word ?) """ return clip.fl_image( lambda pic: np.minimum(255,(factor*pic)). astype('uint8'))
V demonstračním příkladu, jehož zdrojový kód je vypsán pod tímto odstavcem, se budeme snažit do videa přidat barvy, což se nám sice takto primitivním filtrem samozřejmě nepodaří, protože původní film je monochromatický, ovšem vlivem různých chyb ve videu bude ve výsledcích patrný různobarevný šum atd.:
from moviepy.editor import VideoFileClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # velmi primitivni "kolorizace" recolored_clip = clip.fx(colorx, 2.50) # uložení video klipu do jiného souboru ve formátu Ogg/Theora recolored_clip.write_videofile('06_output_recolored.ogv', bitrate='700000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing07_colorize.htm
10. Nastavení okrajů okolo videa
Poměrně užitečným filtrem, který má všestranné využití, je filtr určený pro vytvoření okraje okolo jednotlivých snímků. Tento filtr se jmenuje margin a předává se mu požadovaná šířka okraje zadaná v pixelech. Výsledkem aplikace filtru je opět nové video, takže lze zápis provést na jediném řádku; ihned za volání konstruktoru VideoFileClip (původní video ovšem již nebudeme mít k dispozici):
from moviepy.editor import VideoFileClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False).margin(20) # uložení video klipu do jiného souboru ve formátu Ogg/Theora clip.write_videofile('08_output_with_margin.ogv', bitrate='700000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing08_margin.htm
11. Aplikace masky na všechny snímky videa
V mnoha situacích, například při míchání většího množství zdrojových videí, přidávání titulků do videa, aplikaci selektivního filtru atd. se setkáme s nutností aplikovat masku na zdrojové video, přičemž výsledkem bude sekvence snímků, v nichž budou barvové složky jednotlivých pixelů vynásobeny hodnotou přečtenou z masky. V knihovně MoviePy je maska představována dvourozměrným polem hodnot ležících v rozsahu 0,0 až 1,0, přičemž by toto pole mělo mít stejné rozměry, jaké je rozlišení snímků ve vstupním videu. Pokud budou použity pouze hodnoty 0,0 a 1,0, bude se aplikovat bitová maska, ale ve skutečnosti je možné použít celý rozsah (reálných) hodnot mezi nulou a jedničkou. Taková maska může být na vstupu představována rastrovým obrázkem reprezentovaným ve stupních šedi (speciální a nejčastěji používaný případ monohromatických obrázků). Následuje příklad masky speciálně vytvořené pro naše testovací vstupní video:
![](https://i.iinfo.cz/images/381/mask-png-1.png)
Obrázek 1: Maska, která bude použita v dalším demonstračním příkladu.
Maska představovaná rastrovým obrázkem se načte příkazem, jehož výsledkem bude jednosnímkový video klip:
# načtení masky mask = ImageClip('mask.png', ismask=True)
Existuje větší množství způsobů aplikace takové masky, ovšem nejčastěji se setkáme s využitím třídy nazvané CompositeVideoClips, která vytvoří nový videoklip na základě pole videoklipů, které jsou specifikovány v konstruktoru této třídy. V našem případě se bude jednat o jediný videoklip, ovšem s nastavenou maskou, která se při kompozici automaticky aplikuje:
# aplikace masky final = CompositeVideoClip([clip.set_mask(mask)])
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing09_masking.htm
Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # načtení masky mask = ImageClip('mask.png', ismask=True) # aplikace masky final = CompositeVideoClip([clip.set_mask(mask)]) # uložení video klipu do jiného souboru ve formátu Ogg/Theora final.write_videofile('09_output_masked.ogv', bitrate='600000')
12. Jednoduchý filtr pro inverzi všech snímků
Další filtr je skutečně velmi jednoduchý, protože slouží pro inverzi všech snímků načtených ze zdrojového videa (přesněji řečeno pro inverzi všech pixelů ve snímcích). I samotná implementace tohoto filtru je pouze dvouřádková:
def invert_colors(clip): """ Returns the color-inversed clip. The values of all pixels are replaced with (255-v) or (1-v) for masks Black becomes white, green becomes purple, etc. """ maxi = (1.0 if clip.ismask else 255) return clip.fl_image(lambda f : maxi - f)
Následuje příklad, který ukazuje způsob použití tohoto jednoduchého filtru:
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # inverzní video inversed_clip = clip.fx(invert_colors) # uložení video klipu do jiného souboru ve formátu Ogg/Theora inversed_clip.write_videofile('10_inverse_video.ogv', bitrate='600000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing10_inverse_video.htm
13. Rozmazání videa v čase (motion blur)
Další filtr dostupný v knihovně MoviePy, s nímž se v dnešním článku seznámíme, je již implementačně komplikovanější, než filtry popsané v předchozích kapitolách. Zatímco se totiž předešlé filtry postupně aplikovaly na jednotlivé snímky čtené ze zdrojového videa, je filtr nazvaný poněkud nepřesně supersample aplikován na několik snímků videa v nastaveném rozmezí. Odpovídající pixely všech snímků na vstupu jsou zprůměrovány a výsledné dvourozměrné pole průměrných hodnot je následně použito pro vytvoření snímku výstupního videa. Průměr se počítá pro jednotlivé barvové složky zvlášť. Tomuto filtru se předávají dva parametry:
Parametr | Význam |
---|---|
d | určuje časový interval ve vstupním videu [t-d, t+d], ze kterého se budou získávat zdrojové snímky |
nframes | určuje celkový (či maximální) počet snímků ve zvoleném intervalu, z nichž se bude počítat průměr |
V následujícím demonstračním příkladu je časový interval velmi krátký a současně je počet snímků pro zprůměrování nastaven na hodnotu 10. Výsledkem bude klasický efekt „rozmazání pohybem“ neboli motion blur (ve skutečnosti může nastat situace, kdy se bude průměrovat méně než deset snímků – vše zde záleží na hodnotě FPS vstupního videa).
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # aplikace rozmazání pohybem blurred_clip = clip.fx(supersample, 0.25, 10) # uložení video klipu do jiného souboru ve formátu Ogg/Theora blurred_clip.write_videofile('11_motion_blur.ogv', bitrate='600000')
Výsledné video vytvořené tímto příkladem naleznete na adrese:
https://tisnik.github.io/moviepy-videos/videoprocessing11_motion_blur.htm
14. Rozmazání s využitím vzdálenějších snímků
Filtr supersample, s nímž jsme se ve stručnosti seznámili v předchozí kapitole je však možné použít i zcela opačným způsobem – nastavením časového intervalu na poměrně vysokou hodnotu (zde konkrétně na jednu sekundu) a snížením počtu snímků pro průměrování (zde na pouhých pět snímků):
# aplikace rozmazáni pohybem blurred_clip = clip.fx(supersample, 1, 5)
Výsledek aplikace tohoto filtru bude odlišný, protože se ve videu budou prolínat tři „reality“ posunuté od sebe o jednu sekundu (minulost, současnost, budoucnost), což je ostatně patrné i po otevření následujícího videa:
https://tisnik.github.io/moviepy-videos/videoprocessing12_motion_blur_B.htm
Následuje výpis upraveného demonstračního příkladu:
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # aplikace rozmazáni pohybem blurred_clip = clip.fx(supersample, 1, 5) # uložení video klipu do jiného souboru ve formátu Ogg/Theora blurred_clip.write_videofile('12_motion_blur.ogv', bitrate='600000')
15. Jednoduchá kompozice typu „obraz v obraze“
Velmi zajímavých efektů lze dosáhnout kompozicí většího množství zdrojových videí do jediného videa výstupního. Možností, jak vstupní videa zkombinovat, existuje hned několik. V této kapitole si ukážeme kompozici typu „obraz v obraze“, kdy se ve výstupním videu vytvoří matice, přičemž se do buněk této matice ukládají vstupní videa:
# vytvoření pole 2×2 s video klipy final_clip = clips_array([[clip1, clip2], [clip3, clip4]])
Samozřejmě nejsme omezeni pouze maticí 2×2 video klipy, ale lze použít libovolně velkou matici. Některé buňky mohou být zaplněny statickým obrázkem typu ImageClip atd. V následujícím příkladu se vytvoří matice 2×2 video klipy obsahující stejná videa. Povšimněte si, že výsledné video má rozlišení snímků 1280×720 pixelů, a to z toho důvodu, že vstupní videa mají rozlišení 640×360 pixelů:
https://tisnik.github.io/moviepy-videos/videoprocessing13_clip_array.htm
Zdrojový kód příkladu, který vytvoří matici 2×2 videoklipů, vypadá následovně:
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.editor import clips_array from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # vytvoření pole 2×2 s video klipy final_clip = clips_array([[clip, clip], [clip, clip]]) # uložení video klipu do jiného souboru ve formátu Ogg/Theora final_clip.write_videofile('13_clip_array.ogv', bitrate='600000')
16. Vytvoření jednoduché pipeline s uložením výsledku ve formě matice čtyř videoklipů
Nyní si ukažme, jakým způsobem lze zkonstruovat různé „pipeline“, které na videa aplikují větší množství filtrů, spojují videa dohromady, například s využitím třídy CompositeVideoClip apod. Vzhledem k tomu, že výsledkem aplikace filtru na vstupní video je vždy nové video představované instancí potomka třídy VideoClip, můžeme na video aplikovat více filtrů za sebou:
clip = VideoFileClip('input_video.mp4', audio=False) blurred = clip.fx(supersample, 0.25, 10) faster = blurred.speedx(1.5) sub_clip = faster.subclip(5.0, 10.0) colorized = subclip.fx(colorx, 2.50) with_margin = colorized.margin(20)
Samozřejmě je možné vše zapsat na jediný řádek:
clip = VideoFileClip('input_video.mp4', audio=False).fx(supersample, 0.25, 10).speedx(1.5).subclip(5.0, 10.0).fx(colorx, 2.50).margin(20)
Větší množství pipeline se sloučí do matice m×n videí například takto:
# vytvoření pole 2×2 s video klipy final_clip = clips_array([[clip, clip2], [clip3, clip4]])
Popř. je možné videoklipy spojit za sebe:
clips = [clip1, clip2, clip3, clip4] concat_clip = concatenate_videoclips(clips, method="compose")
V dalším příkladu vytvoříme následující video ukazující jak původní (zdrojový) videoklip, tak i jeho tři modifikace:
https://tisnik.github.io/moviepy-videos/videoprocessing14_clip_array.htm
Opět si ukažme, jak vypadá úplný zdrojový kód tohoto demonstračního příkladu:
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.editor import clips_array from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False) # načtení masky mask = ImageClip('mask.png', ismask=True) # aplikace masky clip2 = CompositeVideoClip([clip.set_mask(mask)]) # aplikace rozmazání pohybem clip3 = clip.fx(supersample, 0.25, 10) # aplikace rozmazání pohybem clip4 = clip.fx(supersample, 1, 5) # vytvoření pole 2×2 s video klipy final_clip = clips_array([[clip, clip2], [clip3, clip4]]) # uložení video klipu do jiného souboru ve formátu Ogg/Theora final_clip.write_videofile('14_clip_array.ogv', bitrate='800000')
Filtr je samozřejmě možné aplikovat již na vstupní video, což je ukázáno na předposledním příkladu, v němž se okolo jednotlivých částí vytvořil desetipixelový okraj:
https://tisnik.github.io/moviepy-videos/videoprocessing15_clip_with_margin.htm
Zdrojový kód tohoto příkladu vypadá následovně:
from moviepy.editor import ImageClip, VideoFileClip, CompositeVideoClip from moviepy.editor import clips_array from moviepy.video.fx.all import * # načtení video klipu uloženého v kontejneru MPEG-4 clip = VideoFileClip('input_video.mp4', audio=False).margin(10) # načtení masky mask = ImageClip('mask.png', ismask=True) # aplikace masky clip2 = CompositeVideoClip([clip.set_mask(mask)]) # aplikace rozmazání pohybem clip3 = clip.fx(supersample, 0.25, 10) # aplikace rozmazání pohybem clip4 = clip.fx(supersample, 1, 5) # vytvoření pole 2×2 s video klipy final_clip = clips_array([[clip, clip2], [clip3, clip4]]) # uložení video klipu do jiného souboru ve formátu Ogg/Theora final_clip.write_videofile('15_clip_array_with_margin.ogv', bitrate='800000')
17. Vytvoření videa z jednotlivých snímků získaných z rastrových obrázků
V závěrečné části dnešního článku si ukážeme skript sloužící k vytvoření videa ze snímků, které jsou načteny z rastrových obrázků (zde konkrétně z obrázků uložených ve formátu PNG). Tento příklad bude sloužit jako základ pro příklady popsané příště, ve kterých se budeme zabývat tvorbou vizualizací, programováním vlastních filtrů a částečně i analýzou obrazu.
Ve skriptu se nejdříve získá seznam všech souborů s koncovkou „.png“, tento seznam se setřídí, z každého obrázku se vytvoří samostatný (jednosnímkový) videoklip představovaný instancí třídy ImageClip a na závěr se tyto krátké videoklipy spojí dohromady funkcí concatenate_videoclips, která akceptuje seznam videoklipů a nepovinně taktéž určení, jakým způsobem se tyto videoklipy mají spojit. V případě potřeby je samozřejmě možné do celého zpracování přidat nějaký filtr, například pro prolínání obrázků apod.:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import os import glob from moviepy.editor import ImageClip, concatenate_videoclips fps = 10 frame_duration = 2 # ziskani serazeneho seznamu souboru *.png base_dir = os.path.realpath(".") file_list = glob.glob('*.png') file_list_sorted = sorted(file_list) # vytvoreni sady objektu typu ImageClip clips = [ImageClip(filename).set_duration(frame_duration) for filename in file_list_sorted] # kompozice vsech kratkych video klipu concat_clip = concatenate_videoclips(clips, method="compose") # ulozeni vysledneho video klipu do souboru ve formatu Ogg/Theora concat_clip.write_videofile("test.ogv", fps=fps)
18. Repositáře s demonstračními příklady a vygenerovanými videi
Zdrojové kódy všech dnes popsaných demonstračních příkladů určených pro Python 3 byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/moviepy-examples (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, stále doslova několik kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
Druhý repositář obsahuje všechna videa uložená do formátu Ogg/Vorbis, která byla vygenerována demonstračními příklady. Odkazy na jednotlivá videa jsou uvedeny v následující tabulce:
19. Odkazy na Internetu
- MoviePy 0.2.3.3 na PyPi
https://pypi.org/project/moviepy/ - MoviePy na GitHubu
https://github.com/Zulko/moviepy - MoviePy – dokumentace
http://zulko.github.io/moviepy/ - MoviePy – galerie
http://zulko.github.io/moviepy/gallery.html - Data Animations With Python and MoviePy
https://zulko.github.io/blog/2014/11/29/data-animations-with-python-and-moviepy/ - Porovnání formátů Ogg Theora a H.264
https://www.root.cz/zpravicky/porovnani-formatu-ogg-theora-a-h-264/ - Případ GIF
https://www.root.cz/clanky/pripad-gif/ - Pravda a mýty o GIFu
https://www.root.cz/clanky/pravda-a-myty-o-gifu/ - Anatomie grafického formátu GIF
https://www.root.cz/clanky/anatomie-grafickeho-formatu-gif/ - GIF: animace a konkurence
https://www.root.cz/clanky/gif-animace-a-konkurence/ - Two python modules : MoviePy and images2gif – part 001
http://free-tutorials.org/two-python-modules-moviepy-and-images2gif-part-001/ - images2gif
https://pypi.org/project/images2gif/ - Making GIFs from video files with Python
https://www.devbattles.com/en/sand/post-345-Making+GIFs+From+Video+Files+With+Python - GIF89a specification
https://www.w3.org/Graphics/GIF/spec-gif89a.txt - MPEG-4 Part 14
https://en.wikipedia.org/wiki/MPEG-4_Part14 - Theora video compression
https://www.theora.org/ - Theora
https://en.wikipedia.org/wiki/Theora - NumPy
http://www.numpy.org/ - numpy 1.14.2 (on PyPi)
https://pypi.org/project/numpy/ - Integrovaná vývojová prostředí ve Fedoře: praktické použití IPython Notebooku a knihovny Numpy
https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-prakticke-pouziti-ipython-notebooku-a-knihovny-numpy/ - Integrovaná vývojová prostředí ve Fedoře: praktické použití IPython Notebooku a knihovny Numpy (2.část)
https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-prakticke-pouziti-ipython-notebooku-a-knihovny-numpy-2-cast/ - Non-linear editing system
https://en.wikipedia.org/wiki/Non-linear_editing_system - Popis barvových map modulu matplotlib.cm
https://gist.github.com/endolith/2719900#id7 - Ukázky (palety) barvových map modulu matplotlib.cm
http://matplotlib.org/examples/color/colormaps_reference.html - Customising contour plots in matplotlib
https://philbull.wordpress.com/2012/12/27/customising-contour-plots-in-matplotlib/ - NumPy Home Page
http://www.numpy.org/ - NumPy v1.10 Manual
http://docs.scipy.org/doc/numpy/index.html - NumPy (Wikipedia)
https://en.wikipedia.org/wiki/NumPy - Monitoring sucha
http://portal.chmi.cz/aktualni-situace/sucho