What's new
Carbonite

South Africa's Top Online Tech Classifieds!
Register a free account today to become a member! (No Under 18's)
Home of C.U.D.

3 x 3 Mean Blur in C#

Zaggermeister

Well Known Member
Rating - 100%
13   0   0
Joined
Sep 3, 2015
Messages
496
Reaction score
53
Points
2,035
Age
26
Location
Potchefstroom
Hey guys, got a quick question.

So I'm trying to blur a large image using a mean 3*3 mask. I helped a friend of mine and we managed to blur smaller images (under 1920*1080) in less than 5 seconds average. I tried to do it on my own and used snippets but different methods (the method closest as to which our lecturer wants) but ended up with a 1080 picture taking 35 seconds. I managed to get that down to 20 seconds average (same picture) but our test file is a 17.2MB satellite image which we need to blur. At this stage it is taking me minutes to blur the image and his program managed to blur it in a lot less. I could ask him to help me with my code but he C+Ped it and spiced it up a bit so he himself doesn't really know why it works.

The concept is simple though, the 3*3 matrix moves over a pixel, calculates the average of the squares around the pixel and then applies the average to that pixel.

C#:
        public void Smooth(Bitmap bmpInput)
        {

            Bitmap temp,final;
            int r, g, b;
            float sumR, sumB, sumG;
            Color c;

            temp = bmpInput;

            for (int i = 0; i <= temp.Width - 3; i++)
                for (int j = 0; j <= temp.Height - 3; j++)
                {
                    sumB = 0;
                    sumG = 0;
                    sumR = 0;
                    for (int x = i; x <= i + 2; x++)
                        for (int y = j; y <= j + 2; y++)
                        {
                            c = temp.GetPixel(x, y);
                            r = c.R;
                            g = c.G;
                            b = c.B;
                            sumR = sumR + r;
                            sumG = sumG + g;
                            sumB = sumB + b;
                        }

                    int colorR = (int)(sumR / 9);
                    int colorG = (int)(sumG / 9);
                    int colorB = (int)(sumB / 9);
                    //int colorR = (int)Math.Round(sumR / 9, 10);
                    //int colorG = (int)Math.Round(sumG / 9, 10);
                    //int colorB = (int)Math.Round(sumB / 9, 10);
                    temp.SetPixel(i + 1, j + 1, Color.FromArgb(colorR, colorG, colorB));

                }

            final = temp;
            final.Save("C:\\Users\\The Machine\\Desktop\\test.jpg");

        }

This is my method, the commented lines were my original but between the original and the new lines the end product doesn't visually change. I'm still quite far from all the functions we need, so at this point it is still spaghetti code, so don't judge :p

If anyone can think of a way to optimise this a bit, feel free to let me know.
 
I managed to shorten the time a bit. Now I need to split the image into parts based on the user's thread selection. (The user picks an amount of threads and based on that, that's how many threads need to be used to process the image.)

Anyone got experience with threading in C#?
 
Possible speed increase:
Must it be a 3x3 matrix or can it be any type of blur?

How about adding the top/bottom/left/right pixels and bitshifting, then adding the centre pixel and bitshifting again.

Bitshifts are fast, and divides are slow.

PS: I come from a microcontroller background and am more used to optimizing for microcontrollers. I also am an Engineer, so my maths is more like close enough for practical purposes, rather than mathematically correct.
 
I managed to shorten the time a bit. Now I need to split the image into parts based on the user's thread selection. (The user picks an amount of threads and based on that, that's how many threads need to be used to process the image.)

Anyone got experience with threading in C#?
The easiest way would be parallel?

Parallel.ForEach(
List<>,
new ParallelOptions { MaxDegreeOfParallelism = {THREADCOUNT} },
ProcessingMethod
);

Pass in your list of stuff to process, threadcount as an int, and then define a method to handle the work.
Or you could handle it inline with an anonymous method
 
Instead of doing a moving 3x3 pixel box, can you not just a do a horisontal blur (left and right pixel) and then a vertical blur (above and below blur)?

PS: Also, remember to keep the previous values in RAM and not re-read it.
 
Last edited:
Possible speed increase:
Must it be a 3x3 matrix or can it be any type of blur?

How about adding the top/bottom/left/right pixels and bitshifting, then adding the centre pixel and bitshifting again.

Bitshifts are fast, and divides are slow.

PS: I come from a microcontroller background and am more used to optimizing for microcontrollers. I also am an Engineer, so my maths is more like close enough for practical purposes, rather than mathematically correct.

Thanks for the feedback, yes it needs to be a 3*3 matrix. For larger pictures we however need to use a larger matrix in order to visually differentiate it. Making it larger isn't really a problem, same concept with some numbers changed.
 
Instead of doing a moving 3x3 pixel box, can you not just a do a horisontal blur (left and right pixel) and then a vertical blur (above and below blur)?

PS: Also, remember to keep the previous values in RAM and not re-read it.

Needs to be a boxed 3*3 matrix, and I create a new object for the blurred image which is then saved as the new image. I do however want to change my method from receiving a full picture (bitmap) into receiving only bits and processing that to speed up the process.
 
Well, you can do a multiply by seven shift by 64. That will be much faster than dividing. And loss will be under 2%. You shouldn't notice.

So replace:
Code:
int colorR = (int)(sumR / 9);
with,
Code:
int colorR = (int)(sumR / * 7 >> 6);

PS: I was right! According to this website doing a horisontal and vertical is equivalent to doing a box:
Java Image Processing - Blurring for Beginners
 
Last edited:
Well, you can do a multiply by seven shift by 64. That will be much faster than dividing. And loss will be under 2%. You shouldn't notice.

So replace:
Code:
int colorR = (int)(sumR / 9);
with,
Code:
int colorR = (int)(sumR / * 7 >> 6);

PS: I was right! According to this website doing a horisontal and vertical is equivalent to doing a box:
Java Image Processing - Blurring for Beginners
Thanks for that, I however did realise that my timer wasn't accurate. It ran from the application startup until the image was processed instead of running from the start of the image processing. Brought my 4 second image processing down to 0.15 average without threading.
 
Holy necro.

Couldn't help myself, attempted it and conquered it.

See here
 

Users who are viewing this thread

Back
Top Bottom