C# - Filtracja Splotowa

0

Witam, właśnie piszę aplikację do filtracji splotowej obrazu w bitmapie.

Tutaj jest funkcja filtracji:

        public void filtr(int[] maska)
        {
            bitmapa = null;
            int waga = 0;
            for (int i = 1; i < maska.Length; i++) waga = waga + maska[i];
            bitmapa = (Bitmap)(pictureBox2.Image);
            
                for (int i = 1; i < bitmapa.Width - 1; i++)
                {
                    for (int j = 1; j < bitmapa.Height - 1; j++)
                    {

                        int sumaR = 0;
                        int sumaG = 0;
                        int sumaB = 0;
                        pxl = bitmapa.GetPixel(i, j);
                        Color pom_pxl = bitmapa.GetPixel(i - 1, j - 1);
                        Color pom_pxl2 = bitmapa.GetPixel(i - 1, j);
                        Color pom_pxl3 = bitmapa.GetPixel(i - 1, j + 1);
                        Color pom_pxl4 = bitmapa.GetPixel(i, j - 1);
                        Color pom_pxl5 = bitmapa.GetPixel(i, j + 1);
                        Color pom_pxl6 = bitmapa.GetPixel(i + 1, j - 1);
                        Color pom_pxl7 = bitmapa.GetPixel(i + 1, j);
                        Color pom_pxl8 = bitmapa.GetPixel(i + 1, j + 1);
                        //R
                        int[] tabR = new int[] {Convert.ToInt16(pom_pxl.R),Convert.ToInt16(pom_pxl2.R),Convert.ToInt16(pom_pxl3.R),
                                                Convert.ToInt16(pom_pxl4.R),Convert.ToInt16(pxl.R),Convert.ToInt16(pom_pxl5.R),
                                                Convert.ToInt16(pom_pxl6.R),Convert.ToInt16(pom_pxl7.R),Convert.ToInt16(pom_pxl8.R)};
                        for (int k = 0; k < maska.Length; k++) tabR[k] *= maska[k];
                        for (int k = 0; k < maska.Length; k++) sumaR += tabR[k];

                        if (waga != 0) sumaR = Convert.ToInt16(sumaR / waga);
                        if (sumaR < 0) sumaR = 0;
                        if (sumaR > 255) sumaR = 255;

                        //G

                        int[] tabG = new int[] {Convert.ToInt16(pom_pxl.G),Convert.ToInt16(pom_pxl2.G),Convert.ToInt16(pom_pxl3.G),
                                               Convert.ToInt16(pom_pxl4.G),Convert.ToInt16(pxl.G),Convert.ToInt16(pom_pxl5.G),
                                               Convert.ToInt16(pom_pxl6.G),Convert.ToInt16(pom_pxl7.G),Convert.ToInt16(pom_pxl8.G)};
                        for (int k = 0; k < 9; k++) tabG[k] *= maska[k];
                        for (int k = 0; k < 9; k++) sumaG += tabG[k];
                        if (waga != 0) sumaG = Convert.ToInt16(sumaG / waga);
                        if (sumaG < 0) sumaG = 0;
                        if (sumaG > 255) sumaG = 255;

                        //B

                        int[] tabB = new int[] {Convert.ToInt16(pom_pxl.B),Convert.ToInt16(pom_pxl2.B),Convert.ToInt16(pom_pxl3.B),
                                                Convert.ToInt16(pom_pxl4.B),Convert.ToInt16(pxl.B),Convert.ToInt16(pom_pxl5.B),
                                                Convert.ToInt16(pom_pxl6.B),Convert.ToInt16(pom_pxl7.B),Convert.ToInt16(pom_pxl8.B)};
                        for (int k = 0; k < 9; k++) tabB[k] *= maska[k];
                        for (int k = 0; k < 9; k++) sumaB += tabB[k];
                        if (waga != 0) sumaB = Convert.ToInt16(sumaB / waga);
                        if (sumaB < 0) sumaB = 0;
                        if (sumaB > 255) sumaB = 255;


                        bitmapa.SetPixel(i, j, Color.FromArgb(sumaR, sumaG, sumaB));
                    }
                    progressBar1.Value = (int)((i * 100) / bitmapa.Width);
                }
            
            pictureBox2.Image = bitmapa;
            

        }

Do funkcji przekazuje tablice jednowymiarową z maską, dla przykładu (filtr sobela):

        private void button6_Click(object sender, EventArgs e)
        {
            int[] maska = new int[] { 1, 0, -1, 2, 0, -2, 1, 0, -1 };
            filtr(maska);
        }

Przekazuje maskę:
1 2 1
0 0 0
-1 -2 -1

Problem w tym, że po zastosowaniu tego filtru wychodzi mi taki obraz wynikowy:
user image

Co może być nie tak? Próbowałem na różnych maskach i wyniki są podobne.

1

Czytaj z jednej bitmapy, zapisuj piksele do drugiej. Nie operuj „w miejscu” bo psujesz bitmapę.

0

Poprawiłem kod:

public void filtr(int[] maska)
        {
            int waga = 0;
            for (int i = 1; i < maska.Length; i++) waga = waga + maska[i];
            bitmapa = (Bitmap)(pictureBox2.Image);
            Bitmap bitmapa2 = bitmapa;
                for (int i = 1; i < bitmapa.Width - 1; i++)
                {
                    for (int j = 1; j < bitmapa.Height - 1; j++)
                    {

                        int sumaR = 0;
                        int sumaG = 0;
                        int sumaB = 0;
                        pxl = bitmapa.GetPixel(i, j);
                        Color pom_pxl = bitmapa.GetPixel(i - 1, j - 1);
                        Color pom_pxl2 = bitmapa.GetPixel(i - 1, j);
                        Color pom_pxl3 = bitmapa.GetPixel(i - 1, j + 1);
                        Color pom_pxl4 = bitmapa.GetPixel(i, j - 1);
                        Color pom_pxl5 = bitmapa.GetPixel(i, j + 1);
                        Color pom_pxl6 = bitmapa.GetPixel(i + 1, j - 1);
                        Color pom_pxl7 = bitmapa.GetPixel(i + 1, j);
                        Color pom_pxl8 = bitmapa.GetPixel(i + 1, j + 1);
                        //R
                        int[] tabR = new int[] {Convert.ToInt16(pom_pxl.R),Convert.ToInt16(pom_pxl2.R),Convert.ToInt16(pom_pxl3.R),
                                                Convert.ToInt16(pom_pxl4.R),Convert.ToInt16(pxl.R),Convert.ToInt16(pom_pxl5.R),
                                                Convert.ToInt16(pom_pxl6.R),Convert.ToInt16(pom_pxl7.R),Convert.ToInt16(pom_pxl8.R)};
                        for (int k = 0; k < maska.Length; k++) tabR[k] *= maska[k];
                        for (int k = 0; k < maska.Length; k++) sumaR += tabR[k];

                        if (waga != 0) sumaR = Convert.ToInt16(sumaR / waga);
                        if (sumaR < 0) sumaR = 0;
                        if (sumaR > 255) sumaR = 255;

                        //G

                        int[] tabG = new int[] {Convert.ToInt16(pom_pxl.G),Convert.ToInt16(pom_pxl2.G),Convert.ToInt16(pom_pxl3.G),
                                               Convert.ToInt16(pom_pxl4.G),Convert.ToInt16(pxl.G),Convert.ToInt16(pom_pxl5.G),
                                               Convert.ToInt16(pom_pxl6.G),Convert.ToInt16(pom_pxl7.G),Convert.ToInt16(pom_pxl8.G)};
                        for (int k = 0; k < 9; k++) tabG[k] *= maska[k];
                        for (int k = 0; k < 9; k++) sumaG += tabG[k];
                        if (waga != 0) sumaG = Convert.ToInt16(sumaG / waga);
                        if (sumaG < 0) sumaG = 0;
                        if (sumaG > 255) sumaG = 255;

                        //B

                        int[] tabB = new int[] {Convert.ToInt16(pom_pxl.B),Convert.ToInt16(pom_pxl2.B),Convert.ToInt16(pom_pxl3.B),
                                                Convert.ToInt16(pom_pxl4.B),Convert.ToInt16(pxl.B),Convert.ToInt16(pom_pxl5.B),
                                                Convert.ToInt16(pom_pxl6.B),Convert.ToInt16(pom_pxl7.B),Convert.ToInt16(pom_pxl8.B)};
                        for (int k = 0; k < 9; k++) tabB[k] *= maska[k];
                        for (int k = 0; k < 9; k++) sumaB += tabB[k];
                        if (waga != 0) sumaB = Convert.ToInt16(sumaB / waga);
                        if (sumaB < 0) sumaB = 0;
                        if (sumaB > 255) sumaB = 255;


                        bitmapa2.SetPixel(i, j, Color.FromArgb(sumaR, sumaG, sumaB));
                    }
                    progressBar1.Value = (int)((i * 100) / bitmapa.Width);
                }
            
            pictureBox2.Image = bitmapa2;
            

        }

Dalej to samo :/

2
int waga = 0;
// ...
if (waga != 0) sumaG = Convert.ToInt16(sumaG / waga);

(dzielenie intów)

Ale poważnie, przepisz to wszystko dla swojego dobra. Cały algorytm można podsumować czymś w rodzaju

public Color MaskPixel(int x0, int y0, int[,] mask) {
    int[] result = new int[3];
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            for (int channel = 0; channel < 3; channel++) {
                result[channel] += pixels[x, y, channel] * mask[x, y];
            }
        }
    }
    return Color.FromArgb(result[0], result[1], result[2]);
}

public void Mask(int[,] mask) {
    for (int x = 1; x < width - 1; x++) {
        for (int y = 1; y < height - 1; y++) {
            new_pixels[x, y] = MaskPixel(x, y, mask);
        }
    }
}

(mając bitmapę w int[,,] pixels). Jak pewnie się już przekonałeś, analizowanie & szukanie błędu w takim rozwlekłym kodzie jak Twój obecny nie jest łatwe.

0

Ok, rozumiem, a jak wywołać tą funkcję w programie? Gdzie jest odwołanie do bitmapy?

0

@zimek125: to był tzw. pseudokod, który masz sobie przerobić ;-)

0

Ok, teraz rozumiem :)
Temat do zamknięcia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1