5.31. Hledání posunu

Porovnávání podle šablony odpovídá na otázku kde je tento výřez uvnitř snímku; skórování podobnosti odpovídá na otázku jak moc jsou si tyto dva obrazy celkově podobné. Mezi nimi leží jiná otázka: oba snímky ukazují stejnou scénu, ale kamera (nebo scéna) se mezi nimi pohnula – o kolik? To je problém posunu a modul image jej řeší jedinou metodou fázové korelace.

5.31.1. Posun pomocí fázové korelace

find_displacement() odhaduje tuhé zarovnání mezi dvěma stejně velkými obrazy pomocí fázové korelace – frekvenční metody, která na každém obraze spustí rychlou Fourierovu transformaci (FFT), vzájemně koreluje jejich fáze a v výsledku najde vrchol. Poloha vrcholu je posun, který oba obrazy zarovná:

d = img.find_displacement(template)

print("shift:", d.x_translation, d.y_translation,
      " response:", d.response)

Vrácený objekt Displacement nese x_translation a y_translation – posun v pixelech v každé ose – plus response, skóre spolehlivosti od 0.0 do 1.0, kde 1.0 je dokonalý vrchol. Odfiltrování detekcí pod response > 0.3 zahodí falešné výsledky, u kterých fázová korelace nikdy nenašla čistý vrchol.

rotation i scale jsou ve výchozím režimu 0.0, resp. 1.0; reálné hodnoty nabývají pouze tehdy, je-li logpolar=True (viz níže).

Tato metoda s sebou nese dvě praktická omezení. Prvním jsou rozměry o mocnině dvou: FFT v jádru fázové korelace je nejrychlejší – a na kameře plně podporovaný pouze – při velikostech jako 32 na 32, 64 na 64 a 128 na 128. Nejčistším nastavením je zachytávat přímo v jedné z těchto velikostí předáním rozlišení metodě framesize() jako n-tice:

csi0.framesize((64, 64))

Aplikace, která potřebuje posun z většího snímku, místo toho vyřízne z oblasti, na které jí záleží, výřez o mocnině dvou a na něm spustí porovnávač.

Druhým jsou vstupy stejné velikosti: roi a template_roi musí vybírat shodné šířky a výšky, jinak porovnávač volání odmítne. Dvě zachycení ze stejné kamery ve stejné konfiguraci to splňují automaticky; zachycený snímek porovnávaný s načtenou referencí potřebuje oba nejprve oříznout na shodné výřezy o mocnině dvou.

5.31.2. Rotace a měřítko pomocí log-polární transformace

Výchozí režim hledá pouze posun. Když se dva snímky liší také v rotaci okolo zvoleného středu nebo v měřítku okolo téhož středu, spuštění fázové korelace na log-polární reprojekci každého obrazu změní tyto parametry na posun v log-polárním souřadnicovém systému – který týž porovnávač fázové korelace dokáže obnovit:

d = img.find_displacement(template, logpolar=True)

print("rotation rad:", d.rotation,
      " scale:", d.scale,
      " response:", d.response)

S logpolar=True metoda spouští stejnou porovnávací pipeline proti log-polárně promítnutým obrazům místo originálů. Pole rotation a scale výsledku se vracejí vyplněná: rotation je úhel v radiánech mezi dvěma snímky, scale je měřítkový faktor mezi nimi. x_translation a y_translation v tomto režimu ztrácejí smysl (posun podél log-polárních os neodpovídá lineárnímu posunu ve zdroji).

Keyword fix_rotation_scale=True pokrývá mezilehlý případ: oba obrazy se liší jak v posunu, tak v rotaci/měřítku a aplikace potřebuje pouze posun po korekci rotace a měřítka. Porovnávač nejprve spustí log-polární průchod, aby obnovil rotaci a měřítko, aplikuje inverzi na jeden z obrazů a poté spustí průchod pro posun, aby obnovil zbývající posun. Tento příznak má smysl pouze tehdy, je-li logpolar=False – žádá porovnávač v režimu posunu, aby nejprve odstranil rotaci/měřítko.

Vzor z polárních transformací – kartézská → polární → porovnání – je tím, co find_displacement() s logpolar=True dělá v jednom volání. Aplikace uloží při spuštění referenční log-polární výřez, zachytí a log-polárně transformuje každý živý snímek a metoda obnoví rozdíl rotace a měřítka mezi nimi. Pro aplikace, které potřebují sledování invariantní vůči rotaci a měřítku – dokovacího robota, jehož kamera se při přibližování k cíli naklání a přibližuje, stabilizovaný gimbal, který potřebuje vědět, jak se obraz otáčí vůči referenci – je toto standardní konstrukce.

5.31.3. Klasické použití

Nejběžnějším použitím find_displacement() je odhad pohybu mezi snímky v pipeline, která zpracovává pohybující se kameru. Kamera zachytí malý výřez o mocnině 2 ve snímku N, zachytí stejně velký výřez ve snímku N+1, spustí na obou find_displacement() a odečte posun v pixelech mezi nimi. Posun je odhadovaný pohyb kamery (nebo scény, podle toho, čí vztažná soustava je důležitá) mezi dvěma zachyceními, užitečný pro:

  • Snímání ve stylu optického toku – vznášející se dron s kamerou mířící dolů používá posun na jednotlivých snímcích k odhadu svého bočního pohybu a jeho zpětnému přivedení do letového řadiče.

  • Stabilizace obrazu – posun mezi po sobě jdoucími snímky je odečten ze zachyceného obrazu před jeho záznamem nebo přenosem, čímž vzniká plynulejší video proud.

  • Zarovnání při inspekci – skenovací kamera pohybující se podél dopravníku používá posun na jednotlivých snímcích k registraci každého snímku vůči následujícímu a sestavení sešitého pohledu na celý díl.

Každá z těchto aplikací má stejnou podobu: zachyť, posuň, akumuluj do průběžného odhadu, zachyť znovu.