Sesazení fotek v C#

Sesazování fotek do větších celků nebo panorámat je dnes už dobře zvládnutý problém. Existují metody jednodušší i komplikovanější. Je jenom na člověku, kterou metodu si vybere, ne vždy je totiž nejvýhodnější volit vždy tu nejkomplexnější, která funguje na všechny možné typy snímků.

Nedávno jsem potřeboval automaticky sesazovat fotky povrchu, které nejsou vůči sobě otočené, nejsou různě velké nebo nějak opticky deformované. Typická situace pro jednoduchou korelační metodu.

Trocha teorie

…nejen, že nikoho nezabije, ale musíme taky vědět co vytváříme. Budeme uvažovat, že snímky navazují jeden na druhý a že víme přibližně i míru překryvu. Budeme hledat jenom v jeho okolí, aby celá funkce běžela svižně.

Mějme jeden obrázek, který označíme M (jako moving – pohyblivý) a druhý F (fixed – pevný). Budeme postupně přikládat obrázky na sebe na dané souřadnice a počítat hodnotu korelace. Jakmile získáme hodnoty pro všechny očekávané souřadnice, najdeme mezi nimi maximum. V tom bodě můžeme předpokládat, že bude správné místo sesazení. Hodnotu korelace spočítáme podle následujícího vzorce:

Veličina s pruhem označuje průměrnou hodnotu pixelu daného obrázku. Hodnota mi, fi označuje hodnotu i-tého pixelu obrázku M a F. Celkový počet pixelů je N.

Do práce

To znamená, že budeme provádět operaci v několika vnořených cyklech. První dva cykly běží přes všechny možnosti, kde bychom mohli očekávat správné souřadnice sesazení

for (int ys = y_from; ys ‹= y_to; ys++)
{
    for (int xs = x_from; xs ‹= x_to; xs++)
    {

Pro každý krok musíme spočítat novou průměrnou hodnotu pixelu, protože se nám může mezi jednotlivými kroky lišit.

Na tomto místě by bylo dobré zmínit, jak pracovat s jednotlivými barevnými složkami. Beru je jako rovnocenné a výpočet provádíme pro všechny dohromady. Můžete případně provést pro každou složku zvlášť a zkoumat jestli se výsledek liší a podle toho případně zvětšit toleranční pásmo.

Můžeme tak přistoupit k výpočtu průměrné hodnoty jasu pixelů pro oba obrázky. Musíme proto otevřít další cyklus, tentokrát přes všechny body překrývající části obrázku

for (int y = 0; y ‹= lines; y ++)
   {
   for (int x = 0; x ‹ xs; x++)
   {

Je dobré si udělat hned od začátku pořádek v souřadnicích. Jednoduché označení x a y jsem si nechal pro označení aktuálně používaného pixelu.

V každém kroku sečteme všechny tři složky a uložíme si, kolik už jsme prošli pixelů

          // M obraz
          avgA += pA[0] + pA[1] + pA[2];
          // F obraz
          avgB += pB[0] + pB[1] + pB[2];
          // move pointerpB += 3;
          pA += 3;
          N += 3;
     }
     pA += nOffset + n0A;
     pB += n0B;
 }

Zároveň jsme ukončili vnitřní cyklus, který prochází jednotlivé pixely. Dál můžeme už přímo spočítat aritmetický průměr

// mean value of both pictures
 avgA = avgA / N;
 avgB = avgB / N;

Teď už máme všechno připraveno na to, abychom mohli znovu otevřít cyklus, který prochází všechny pixely a spočítáme zvlášť čitatele a zvlášť jmenovatele vzorce nahoře.

for (int y = 0; y ‹= lines; y ++)
   {
   for (int x = 0; x ‹ xs; x++)
   {
        // covariance
        kovariance += (pA[0] - avgA) * (pB[0] - avgB) + (pA[1] - avgA) * (pB[1] - avgB) + (pA[2] - avgA) * (pB[2] - avgB);

        // correlation denomerator
        sumaA += Math.Pow((pA[0] - avgA), 2) + Math.Pow((pA[1] - avgA), 2) + Math.Pow((pA[2] - avgA), 2);
        sumaB += Math.Pow((pB[0] - avgB), 2) + Math.Pow((pB[1] - avgB), 2) + Math.Pow((pB[2] - avgB), 2);

        // move pointer
        pB += 3;
        pA += 3;
    }
pA += nOffset + n0A;
pB += n0B;
}
double result = kovariance / Math.Sqrt(sumaA * sumaB);

Teď už jsme získali výsledek v každém kroku. Je teď na vás jak přistoupíte k hledání maxima. Nicméně pro začátek je dobré si výsledky všechny vykreslovat a porovnávat jestli je to maximum jediné, jestli je výrazné, atd…

Zdrojové kódy zde uvedené je samozřejmě potřeba doplnit o implementaci načítání pointerů obrázků a vlastně i o zbytek potřebného. Tento text nemá sloužit jenom ke kopírování této funkce, ale pro bližší vysvětlení principu.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *