Všechny televizní stanice (alespoň ty které mám chuť někdy sledovat) do vysílaného programu do rohu obrazovky přidávají svoje logo, například Prima, ČT1, atd. Nicméně reklamy jdou zatím na všech stanicích bez loga. Proto se mi detekce loga jeví jako výborná možnost jak detekovat (alespoň s určitou nepřesnou přesností) kde jsou reklamy, a ty pak třeba přeskakovat či rovnou vystřihnout. Často nahrávám pohádky dětem, abych měl od nich aspoň na chvíli přes den klid, když je žena v sauně, v kině, na masáži, nebo na školení osobního rozvoje (sic). A kde to jde, tam reklamy stříhám, protože už tak děckám vymyje mozek samotná TV, natož pak ty reklamy…
Jelikož neumím na internetu hledat, žádný tool na detekci reklam jsem nenašel. A proto jsem se rozhodl, že vymyslím vlastní. Takže, jak na to.
Bod první, dosáhnout cíle bez čtení kompletního videa.
Celý video soubor může mít třeba 3GB, a nejkratší reklama má 30 sekund. Takže načíst a analyzovat celé video mi přijde jako kanón na vrabce, musí to jít líp. Pro detekci loga by tedy logicky měly stačit pouze sample frejmy, řekněme jeden frame každých 30 vteřin. Dá se přistupovat k frejmům bez čtení celého videa? Odpoveď je naštěstí kladná, ano dá. Obecně je ve videu několik různých typů frejmů. Označují se nějak podobně jako I, P a B, a pro nás je důležité, že v televizním vysílání je pravděpodobně dost I frejmů, které představují plně vykreslený obrázek, a které přesně potřebujeme, stačí na ně skočit. Proč si myslím že je jich dost? Je to proto, že když přepnu z jedné stanice na jinou, vidím video obraz poměrně hned, a ne až za pár sekund. Pomocí funkcí ffmpeg je možné seekovat (tedy skákat ve videu) na konkrétní časovou značku a od ní pak na nejbližší I frejm. Takže se dá velmi snadno najít celý frame každých cca 30 vteřin, a vůbec není nutné číst ze souboru žádná data navíc. To ušetří moře času.
Bod druhý, detekce loga
V tuto chvíli tedy máme přístup k obrazové reprezentaci videa každých řekněme 30 vteřin. U dvouhodinové nahrávky to může být nějakých 240 obrázků (budeme jim říkat pivoty, nevím proč). Na některých logo stanice je (tam kde byl pořad), na některých není (tam kde byla reklama). Metod detekce bude asi nespočet, ale já jsem vymyslel vlastní. Jde o to, zprůměrovat všechny pixely ze všech pivotů. Ve videu je každý bod určený svou pozicí „x“ a „y“, a má tři složky (červená, zelená, modrá, tedy RGB). Takže se napíše funkce, která vezme RGB barvy pixelu 1×1 ze všech 240 obrázků, vytvoří průměr (například aritmetický), a výsledkem je nový pixel pro pozici 1×1, který má červenou složku jako průměr všech červených složek, zelenou jako průměr všech zelených, atd, a vše se zopakuje pro všechny pixely videa. Výsledkem je zprůměrovaný obrázek. Ten sám o sobě vypadá dost hnusně, ale poslouží. Zde můžete vidět zprůměrování všech 140 pivot frejmů z nahrávky Show Jana Krause:
Bod třetí, edge detection
Na zprůměrovaném screenu je logo dobře patrné, ale pro naše účely je zde stále hodně ruchu. Většina toho ruchu je ale rozmazaná, a pouze logo má hezké okraje. Toho musíme využít. Pomocí edge detection (vyhledání hran) můžeme logo najít úplně přesně. Jak edge detection funguje? Dá se říct, že algoritmus je celkem jednoduchý. Obrázek se nejprve převede do odstínu šedi (každý pixel se vytvoří sečtením 30% červené složky, 59% zelené a 11% modré, neptejte se mě proč). Zjednodušeně pak na takovémto výsledku se jde pixel po pixelu, a porovnává se, zda pixely okolo jsou výrazně světlejší či výrazně tmavší. Odečte se hodnota levého od pravého, a hodnota horního od dolního, a oba výsledky se sečtou. Trochu složitější algoritmus je popsaný tady (berte to PHP jako pseudo kód, dělat tohle v PHP není úplne optimální). Po odfiltrování příliš světlých bodů dostaneme téměř čistě jen logo stanice:
Bod čtvrtý, pozice loga
V našem výsledku se stále mohou objevovat body mimo logo stanice, proto pro zjištění přesného umístění loga budeme potřebovat spočítat, pro každý řádek a pro každý sloupec, kolik bodů se v nich nachází, a každý bude mít váhu podle své světlosti (tudíž tmavé body vyznačující ostrou hranu budou váženější). Ze získaných dat vypočítáme geometrický průměr a vyhodíme všechny sloupce a všechny řádky, ve kterých se nachází méně bodů než je průměr. Z toho co zbyde pak nejmenší řádek a nejmenší sloupec udávají XY souřadnici horního levého rohu loga, největší řádek a největší sloupec pak dolní pravý roh. Výsledku můžeme dát pár pixelů padding, pro zichr. Získali jsme souřadnice loga, i jak vypadá:
Bod pátý, test frejmů na logo
Teď už jen otestovat všech 240 pivot frejmů, které jsme získali v kroku 1, abychom dostali hrubý odhad toho, kde jsou reklamy a kde nejsou. Na každý pivot frejm v daném čtverci, kde by mělo být logo, použijeme algoritmus na detekci hran („ohraníme“) a porovnáme, na kolik procent se pixely z „ohraněného“ loga nacházejí i v „ohraněném“ čtverci v pivot frejmu. Možná existuje i elegantnější a přesnější metoda, tu jsem ale zatím nevymyslel ani nenašel. A když už jsme schopni najít přibližné intervaly s loga a bez log, můžeme pak několika málo seek()y jednotlivé úseky zpřesnit, a ve výsledku třeba vypsat vteřinové intervaly s logem a bez loga.
Implementace v C++
Celý tenhle koncept zatím existuje jen na úrovni jednotlivých kroků, které jsem si naprogramoval v PHP (neb jinde se na úroveň pixelů v obrazu dostat neumím), což je neoptimální jak hovado. Kdyby chtěl nějaký student co umí pracovat s ffmpeg brigádu, že mi to napíše celé v C++ jako commandline utilitu pro Linux, mám pro to vyhrazeno pár dvoutisícovek, kontaktujte mě v komentářích :) Také uvítám nápady na to, jak lépe poznat, že nějaký frejm obsahuje logo.
Mozno to dokazes lepsie ako parta okolo mythtv, drzim palce.
Ale ak hladas nieco hotove, tak:
http://www.mythtv.org/wiki/Commercial_detection
http://www.mythtv.org/wiki/Mythcommflag-wrapper
Kdo si hraje nezlobí ;-)
Já sice nic nenahrávám (TV doma nemáme a dětem stačí ivysíláni), ale krátky průzkum mi vrátil: "Comskip for Linux released" http://forum.xbmc.org/showthread.php?tid=150084
Navíc nějakou podporu pro přeskakování reklam má i mythTV: http://www.mythtv.org/wiki/Commercial_detection
@tomas m.: krasa.
@aaaaaaa: niektore tv davaju na zaciatku reklamy a na zaciatku programu keyframe, niektore robia plynuly prechod zo strihovej obrazovky s logom na program, napriklad markiza robi plynuly prechod a este k tomu vracia po reklame program o par sekund dozadu (to sa uz vobec neda rucne strihat).
@andrej: je vidiet ze tv nepozeram, plynuly prechod som este nevidel.
Navrat par sekund dozadu moze pri plynulych prechodoch a uputavkach pomoct - idem napriklad 2 sekundy pred stratu loga* a pojdem dopredu, dokedy nenajdem rovnaky snimok. Vdaka tomu to trafim na snimok presne. Pri digitalnom vysielani by to nemusel byt problem. Zase je to len hypoteza a neviem, ci by to fungovalo.
*2 sekundy = odhad trvania prelinacky
Na řešení obdobných problémů je výborná knihovna http://opencv.org
Re[14]:
No moje PHP implementace neumi rozumne cist frejmy z videa, takze pouzije commandline ffmpeg na dump frejmu kazdych 5 vterin. Coz je sama o sobe katastrofa, protoze to neseekuje, ale cte cele video. Par minut to trva urcite.
Pak to dela ten prumerny obrazek, to trva cca asi 3 minuty ze 140 frejmu o rozliseni 720x576. Kdyz vezmu v uvahu, ze to vlastne dela prumery z celkem 720 x 576 x 140 x 3 hodnot (tj pracuje to jenom s 174 milionama cisel), tak bych taky ocekaval ze to bude v C++ hotove do vteriny.
Ahoj,
zajímavé, sám jsem na to před pár lety myslel (když jsme ještě bydleli v lokalitě pokryté TV signálem :-).
Pak jsem ale nakonfiguroval mythtv a v něm přeskakování reklam fungovalo obstojně a hlavně to díky klient-server architektuře přineslo možnost pouštět i živé pořady na více místech a pro mě hlavní cool fičura byla pauza v živém vysílání a možnost přetočit zpět.
Co se týče samotné detekce, napadlo mě také, že lze docela spolehlivě detekovat reklamy podle zvukové stopy - reklamy jsou minimálně o 3dB hlasitější. Pravděpodobně by šlo i detekovat jingle, který tv vysílá na začátku reklamního bloku.
Věřím, že na "rychlé" vystřižení loga by to mohlo fungovat, ale podle mých zkušeností s ručním "vyzobáváním" reklam je situace mnohem horší:
- občasně animovaná loga jsou vcelku malý problém, obvykle je animace až "po reklamě",
- před reklamou bývá nějaké "znělka" v té může logo zůstávat, po vystřižení reklam by ve filmu zbyla,
- po reklamách bývají upoutávky, opět někdy (zřídka) s logem,
- během vysílání se přepínají různá obrazová rozlišení (film 4:3, reklamy 16:9, upoutávky, znělka - poměrně pestré možnosti kombinací),
- většina programů po reklamě film "kousek vrátí"; někdy stačí najít změnu scény, ovšem tam zrovna nemusí vyjít I-frame...,
- na konci před reklamou a začátku po reklamě mohou mít překrývající se části jinak rozmístěné I-frame (a je nanejvýš vhodné začínat klíčovým snímkem),
- zvuk je někdy o část snímku posunutý, takže ve filmu zůstane nepěkný lupanec, v horším případě kus znělky,
- najít stejný snímek před a po reklamě je problematické, neboť nejsou "bajtově" shodné.
Čili: radši to řeším ručně.
Okay. Dalsiu vec ktoru mozes zvazit je detekcia hlasitosti zvuku.
Reklamy na kazdej stanici idu cca 10% hlasnejsie nez bezny program.
Dalsu vec ktoru zvazit je detekcia "zmeny" obrazu. Myslienka je -> obraz mimo loga sa meni "viac" ako pod pixlami s logom.
Realizacia zaznamenavas max a min svetlost pixelov a zistis napr ak je biele/sede logo tak pixly loga nebudu nikdy cierne akurat tak biele-sede.
Tu detekciu hran mozes robit konvoluciou
optimalizacia:to logo sa "nehybe" takze mozes si jeho polohu nacacheovat a ratat len tam.
Ad hlasitost: s tou hlasitosti to neni tak jednoduche.
- scena ve filmu nemusi byt v plne hlasitosti, ale reklama obycejne zarve na plne koule
- v reklamach/upotavkach pouzivaji hodne silnou kompresi - takze 'hlasitomer' ukaze stejnou hodnotu pro samotny film, i pro reklamu . z toho duvodu neni mozne je pokutovat za zvyseni hlasitosti v reklamach: co se neda zmerit, neda se pouzit jako dukaz. a ze vsichni subjektivne slysi vice? 'to se vam jenom zda'
Není na toto již poměrně slušně konfigurovatelný comskip? http://www.kaashoek.com/comskip/
Teď mě tak napadlo při čtení diskuze - co se vykašlat na logo a místo toho detekovat střih a porovnávat framy? Jestli se nepletu, tak pořád platí to, že poslední cca 3 vteřiny filmu před reklamou se opakují i po skončení reklamy. Nápad tedy zní:
- vytvořit průměr z X framů před střihem a po střihu, ukládat na disk
- porovnávat uložené framy víceméně "každý s každým" - vždy frame vytvořený před střihem s framem vytvořeným po střihu. Pokud se najde těsná shoda, tak s největší pravděpodobností půjde právě ty dva momenty.
Dál mě ještě napadá:
- počítat kadenci střihů - v reklamách by mohl být střih častější
- detekce přehnaně sytých barev
- detekce změny rozlišení, co upozorní na reklamní blok
Samozřejmě se jedná jen o nápady, časově by taková analýza byla zřejmě na opravdu dlouhou dobu.
Tomáš je autorem několika více či méně známých projektů jak z oblasti operačních systémů, tak internetu. V současnosti samozvaný expert na Linux, Bash, PHP a MySQL.
Přečteno 25 942×
Přečteno 23 974×
Přečteno 19 495×
Přečteno 18 281×
Přečteno 12 887×