A jedeme dál ...
Človíčkův Weblog aneb Michal Horák bloguje

Zvětšování a zmenšování obrázků

 | 6.10.2007

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 …

Body

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.

Metoda nejbližšího souseda

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.

Bilineární interpolace

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:

Bilineární interpolace

Kde barva je určena v RGB a musí se spočítat každá šást barvy zvlášť.

Zdrojový kód

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;

        }

Závěrem

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 19529x zobrazen. Pokud se vám líbil můžete si jej zalinkovat: Linkuj.cz, Del.icio.us

Komentáře


Přidejte svůj komentář

Přidej komentář

Tipy na přečtení

Kategorie

Vyhledávání

Odkazy

Nejčtenější příspěvky za poslední týden

Poslední příspěvky

"A jedeme dál ..." Človíčkův Weblog aneb Michal Horák bloguje. (c) Michal Horák (Človíček webdesign) 2006