Jestlipak víte jak funguje zvětšování a zmenšování obrázků na počítači? Nevíte? Tak čtěte dál …

Hlavním problémem při zmenšování či zvětšování obrázku je, že potřebujete vykreslit některé body, které neznáte a tak si je musíte nějak odvodit. Existuje několik algoritmů a já se pokusím dva popsat.
Nejjednodušší algoritmus, který asi po nějaké době napadne každého je metoda nejbližšího souseda. Nejdříve si vytvoříme nový obrázek, tak že přepočítáme šířku a výšku obrázku. Pak přes tuto šířku a výšku procházíme body a těm musíme přiřadit barvu. Ale jak vzít správnou barvu? Přepočítáme si souřadnice na starý obrázek, tam nám vyjde nějaké číslo, které není celým číslem. To je problém, protože souřadnice jsou určeny celými čísly 0,…,n. Proto si vezmeme nejbližšího souseda a do obrázku na hledanou pozici vložíme jeho barvu.
Když budeme mít stejný případ jako v předchozím algoritmu, pak u bilineární interpolace se barva bodu na hledané pozici určí z barev sousedních bodů bodu, který máme na starém obrázku. Tato barva se vypočítá pomocí vzorce:
Kde barva je určena v RGB a musí se spočítat každá šást barvy zvlášť.
Tento zdrojový kód jsem dělal na cvičení ve škole, takže nečekejte žádné zázraky. Je velmi pomalý, ale důležité je pochopení problému a funkčnost.
private Bitmap NejblizsiSousedBitmapArray(int percent) {
int vyska = (int)(((double)this.BitmapArray.GetLength(1)/100)*percent);
int sirka = (int)(((double)this.BitmapArray.GetLength(0) / 100) * percent);
richTextBox1.Text += "stara sirka: "+BitmapArray.GetLength(1)+"\n";
richTextBox1.Text += "stara vyska: "+BitmapArray.GetLength(0) + "\n";
Bitmap bitmap = new Bitmap(sirka, vyska);
int xx;
int yy;
for (int y = 0; y < vyska; y++)
{
for (int x = 0; x < sirka; x++)
{
double a = (x * 100) / percent;
double b = (y * 100) / percent;
xx = (int)Math.Truncate(a);
yy = (int)Math.Truncate(b);
bitmap.SetPixel(x, y, this.BitmapArray[xx,yy]);
}
}
return bitmap;
}
private Bitmap BilinearniBitmapArray(int percent)
{
int vyska = (int)(((double)this.BitmapArray.GetLength(1) / 100) * percent);
int sirka = (int)(((double)this.BitmapArray.GetLength(0) / 100) * percent);
Bitmap bitmap = new Bitmap(sirka, vyska);
int xx;
int yy;
double lx;
double ly;
byte red;
byte green;
byte blue;
for (int y = 0; y < vyska; y++)
{
for (int x = 0; x < sirka; x++)
{
double a = (x * 100) / percent;
double b = (y * 100) / percent;
xx = (int)Math.Truncate(a);
yy = (int)Math.Truncate(b);
lx = ((x * 100) / percent) - xx;
ly = ((y * 100) / percent) - yy;
try {
red = (byte)((this.BitmapArray[xx + 1, yy].R - this.BitmapArray[xx, yy].R) * lx + (this.BitmapArray[xx, yy + 1].R - this.BitmapArray[xx, yy].R) * ly + (this.BitmapArray[xx + 1, yy + 1].R - this.BitmapArray[xx + 1, yy].R - this.BitmapArray[xx, yy + 1].R - this.BitmapArray[xx, yy].R) * lx * ly + this.BitmapArray[xx, yy].R);
green = (byte)((this.BitmapArray[xx + 1, yy].G - this.BitmapArray[xx, yy].G) * lx + (this.BitmapArray[xx, yy + 1].G - this.BitmapArray[xx, yy].G) * ly + (this.BitmapArray[xx + 1, yy + 1].G - this.BitmapArray[xx + 1, yy].G - this.BitmapArray[xx, yy + 1].G - this.BitmapArray[xx, yy].G) * lx * ly + this.BitmapArray[xx, yy].G);
blue = (byte)((this.BitmapArray[xx + 1, yy].B - this.BitmapArray[xx, yy].B) * lx + (this.BitmapArray[xx, yy + 1].B - this.BitmapArray[xx, yy].B) * ly + (this.BitmapArray[xx + 1, yy + 1].B - this.BitmapArray[xx + 1, yy].B - this.BitmapArray[xx, yy + 1].B - this.BitmapArray[xx, yy].B) * lx * ly + this.BitmapArray[xx, yy].B);
bitmap.SetPixel(x, y, Color.FromArgb(red, green, blue));
}
catch {
}
}
}
return bitmap;
}
Pro ještě kvalitnější změnu velikosti se používá bikubická interpolace, kterou jsem ještě nedělal, ale pokud budu mít čas, tak bych ji rád naprogramoval. Když se to povede, výsledek přidám sem.
Příspěvek vyšel v Sobotu 6.10.2007 21:04 v kategorii Programování a byl 6479x zobrazen. Pokud se vám líbil můžete si jej zalinkovat: Linkuj.cz, Del.icio.us
"A jedeme dál ..." Človíčkův Weblog aneb Michal Horák bloguje. (c) Michal Horák (Človíček webdesign) 2006