Työssä käsiteltävän algoritmin perustarkoitus on videokuvan muutosten analysointi.
Tätä varten algoritmi pitää sisäisessä muistissaan valitun määrän edellisiä kuvia ja laskee niiden perusteella pikselikohtaisen keskihajonnan. Algoritmin toiminta on esitetty esimerkillä kuvassa \ref{fig_toiminta}.

Algoritmin muut osat liittyvät kuvien esikäsittelyyn ja tulosten jälkikäsittelyyn.
Videokuvat voidaan suodattaa ennen laskentaa konvoluutiosuotimella, jolla voidaan toteuttaa esimerkiksi sumennus tai reunojen tunnistus.
Tuloksena saaduista keskihajonnan arvoista puolestaan voidaan laskea prosenttipiste tai tietyn kynnysarvon ylittävien pikselien määrä.

\begin{figure}
\centering
\newcommand{\pixel}[3][]{
    \pgfmathparse{#3/255*100}
    \pgfmathsetmacro{\temp}{\pgfmathresult}
    \pgfmathparse{(#3<127)*255}
    \pgfmathsetmacro{\tempb}{\pgfmathresult}
    \node (#1) [
        fill=white!\temp!black,
        text=white!\tempb!black
    ] at (#2) {#3};
}
\begin{tikzpicture}
[slanted/.style={x=7mm, y=7mm, yslant=0.7, xscale=0.5,
    every node/.style={yslant=0.7, xscale=0.5, draw, font=\scriptsize, minimum size=7mm}}]

{
\tikzset{x=7mm, y=7mm, every node/.style={draw, font=\scriptsize, minimum size=7mm}}
\pixel{0,0}{255} \pixel[input]{1,0}{255} \pixel{2,0}{0}
\pixel{0,1}{255} \pixel{1,1}{255} \pixel{2,1}{255}
\pixel{0,2}{255} \pixel{1,2}{255} \pixel{2,2}{255}
}

\node [above=2cm] at (input) {Uusin kuva};
\node [draw, shape=circle] at (7mm,-2.05cm) (konvoluutio) {\Large $\ast$};


{
\tikzset{xshift=4cm, yshift=-3cm, slanted}
\pixel{0,0}{255} \pixel{1,0}{198} \pixel{2,0}{141}
\pixel{0,1}{255} \pixel[eka]{1,1}{227} \pixel{2,1}{198}
\pixel{0,2}{255} \pixel{1,2}{255} \pixel{2,2}{255}

\begin{pgfonlayer}{background}
\draw [shift only,thick,dashed] (eka.center)--($(eka.center) - (1cm,0)$);
\end{pgfonlayer}
\draw [shift only,thick,dashed] (eka.center)--($(eka.center) + (2cm,0)$);

\tikzset{shift only, xshift=1.5cm, slanted}
\pixel{0,0}{255} \pixel{1,0}{198} \pixel{2,0}{0}
\pixel{0,1}{255} \pixel[toka]{1,1}{227} \pixel{2,1}{198}
\pixel{0,2}{255} \pixel{1,2}{255} \pixel{2,2}{255}

\draw [shift only,thick,dashed] (toka.center)--($(toka.center) + (2cm,0)$);

\tikzset{shift only, xshift=1.5cm, slanted}
\pixel{0,0}{198} \pixel{1,0}{0} \pixel{2,0}{0}
\pixel{0,1}{227} \pixel[vika]{1,1}{198} \pixel{2,1}{0}
\pixel{0,2}{255} \pixel{1,2}{227} \pixel{2,2}{198}

\draw [shift only,thick,dashed] (vika.center)--($(vika.center) + (2cm,0)$);

\tikzset{shift only, xshift=3cm, yshift=2.5mm, x=7mm, y=7mm, every node/.style={draw, font=\scriptsize, minimum size=7mm}}
\pixel{0,0}{33} \pixel[varbot]{1,0}{114} \pixel{2,0}{81}
\pixel{0,1}{16} \pixel[var]{1,1}{17} \pixel{2,1}{114}
\pixel{0,2}{0} \pixel{1,2}{16} \pixel{2,2}{33}

\tikzset{shift only}
\draw [thick,->] ($(vika) + (1cm,0)$)--($(var) - (1.2cm,0)$);
\draw [thick,dashed] (vika) -- +(1cm,0);
}
Keskihajontataulukon muodostus
\node [below=1.5cm] at (toka) {Kuvapuskuri: $n$ edellistä kuvaa};
\node [above=1.5cm, text width=10em, text centered] at (var) {Pikselikohtaiset keskihajonnat};

\node [node distance=1.75cm, below of=konvoluutio] (kernel) {Konvoluutiokerneli};
\draw [thick,->] (kernel) -- (konvoluutio);
\draw [thick,->] (input) -- (konvoluutio);
\draw [thick,->] (konvoluutio) -- ($(eka) - (1cm,0)$);

\matrix [below=3cm,draw, matrix of nodes, nodes={anchor=east}, inner sep=1mm] at (var) (sorted) {
    114 \\
    |(ppiste)| 114 \\
    81 \\
    33 \\
    33 \\
    17 \\
    16 \\
    16 \\
    0 \\
};

\draw [thick,->] (varbot) -- (sorted) node [midway, right] {Lajittelu};

\node [node distance=2cm, left=of ppiste, text width=10em] (result) {Lopputulos: Keskihajonnan prosenttipiste = 114.};
\draw [thick,->] (ppiste) -- ($(result.east) + (-10mm,0)$);

\end{tikzpicture}
\caption{Algoritmin periaate: videokuvan kukin kuva suodatetaan konvoluutiolla,
jonka jälkeen lasketaan pikselikohtainen keskihajonta $n$ edellisen kuvan ajalta ja siitä prosenttipiste.}
\label{fig_toiminta}
\end{figure}

\section{Osien merkitys}
Työssä ei muutettu olemassaolevan algoritmin toimintaa, jotta sitä käyttäviin sovellusohjelmiin ja parametreihin ei tarvitse tehdä säätöjä.
Alla on kuitenkin lyhyt kuvaus siitä, mikä algoritmin kunkin osan tarkoitus on.

\emph{Konvoluutio:} Kuvat esikäsitellään konvoluutiolla, jonka kernelin sovellusohjelma voi vapaasti määrätä.
Tähän mennessä on käytetty sumennuskerneliä pienten häiriöiden, kuten kamerasta aiheutuvan kohinan, poistoon kuvasta.
Konvoluution joustavuuden vuoksi samaa menetelmää voitaisiin käyttää esimerkiksi reunantunnistukseen tai joidenkin piirteiden korostamiseen kuvassa.

\emph{Keskihajonta:} Keskihajonta toimii algoritmissa muutosten suuruuden mittarina.
Se on laskennallisesti raskaampi kuin esimerkiksi vaihteluvälin laskeminen minimin ja maksimin avulla.
Toisaalta keskihajonta ei ole yhtä herkkä yksittäisille virhetuloksille.
Nopeutuksen kannalta tulevaisuudessa kannattaisi arvioida, voisiko minimi- ja maksimilaskennalla korvata keskihajonnan.

\emph{Prosenttipiste:} Keskihajonnan tuloksista lasketaan useimmiten esimerkiksi 99~\% prosenttipiste. 
Tulokset siis järjestetään suuruusjärjestykseen, ja valitaan se tulos, joka on 99~\%:n kohdalla pienimmästä tuloksesta laskien. Tarkoitus on vähentää yksittäisissä pikseleissä olevien häiriöiden vaikutusta koko tulokseen.

\emph{Kynnysarvo:} Keskihajonnan tuloksista voidaan laskea myös tietyn kynnysarvon ylittävien pikselien määrä.
Tarkoitus on vastaava kuin prosenttipisteen tapauksessa, mutta kynnysarvossa haluttu muutosten suuruus on määrätty ennakolta ja algoritmi laskee, montako pikseliä on muuttunut.

\section{Algoritmin rajapinta}
Algoritmin sovellusohjelmalle näkyvä rajapinta on koostuu pääosin neljästä funktiosta:

\emph{Alustus:} Alustusfunktiolle kerrotaan kuvan leveys, korkeus, kuvatyyppi, puskurin pituus sekä käytettävä konvoluutiokerneli. Se varaa tarvittavat muistipuskurit ja esikäsittelee konvoluutiokernelin. Paluuarvona on osoitin, jonka muut funktiot ottavat parametrina.
Kutsumalla alustusfunktiota useita kertoja voidaan samanaikaisesti käsitellä useaa kuvavirtaa.

\emph{Kuvan syöttö:} Kuvan lisäysfunktiolle annetaan osoitin uuteen kameralta tai tiedostolta saatuun kuvaan.
Funktio suorittaa konvoluution kuvalle ja tallentaa tuloksen sisäiseen puskuriin, sekä päivittää keskihajonnassa käytetyt summataulukot.

\emph{Keskihajonnan laskenta:} Keskihajonnan laskeva funktio käy läpi muistissa pidetyt summataulukot, joiden perusteella se laskee keskihajonnan kullekin pikselille. Tuloksista voidaan laskea joko prosenttipiste, kynnysarvon ylittävien pikselien määrä tai palauttaa jokaisen pikselin keskihajonta taulukossa.

\emph{Muistin vapautus:} Purkamisfunktio poistaa alustusfunktion varaamat puskurit ja vapauttaa muistin.

Virhetilanteet käsitellään palauttamalla funktiosta virhekoodi, joka kertoo virhetilanteen nimen.
Yksinkertaisuuden vuoksi virhekoodi on pelkkä osoitin merkkijonoon, jonka sisältö voi olla esimerkiksi \code{"OUT\_OF\_MEMORY"}. Jos virhettä ei tapahtunut, virhekoodi on nolla.

\section{Tuetut kuvatyypit}
Aiemmassa prototyypissä on käytetty pelkkiä harmaasävykuvia.
Tähän versioon toteutettiin kuitenkin tuki yhteensä kolmelle erilaiselle kuvatyypille.
Harmaasävykuvista tuetaan 8-bittisiä harmaasävyarvoja, ja värikuvista 24- ja 32-bittisiä RGB-formaatteja.
RGB32-tyypin tapauksessa myös jokaisen pikselin neljäs kanava, jota käytetään joskus läpinäkyvyyden ilmaisemiseen, käsitellään vastaavasti kuin värikanavat.
Läpinäkyvyyttä ei varsinaisesti käytetä sovelluksissa, mutta toteutuksen kannalta se ei eroa värikanavista.

Kanavien järjestyksellä kuvissa ei ole varsinaisesti merkitystä algoritmin kannalta, sillä kaikki kanavat käsitellään samalla tavalla.
Tämän vuoksi sama toteutus sopii yhtä hyvin myös esimerkiksi ajoittain käytetyille BGR-kuville, joissa kanavat ovat vain eri järjestyksessä.
Sen sijaan videokäytössä yleisessä YUV-formaatissa kirkkaus- ja värikanavat on erotettu, eikä tämä toteutus siksi sovi niille.

Toteutus tukee kuvia, joissa värisyvyys on 8 bittiä jokaista värikanavaa kohti.
Tulevaisuudessa voi olla tarvetta tukea myös 16-bittisiä kuvia, joita käyttäen kamera pystyy käsittelemään laajempaa valoisuusaluetta eli suurempia kontrasteja.
Tämä vaatii kuitenkin kaikkien bittileveyksien kaksinkertaistamista, joten sitä ei toistaiseksi toteutettu.