Click here to Skip to main content
15,867,869 members
Articles / Programming Languages / C#
Tip/Trick

Very Fast Image Blur in C# using Direct Bit Manipulation in Pure .NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
17 Apr 2023CPOL1 min read 13.3K   278   11   11
Very fast image processing without use of unsafe code
In this tip, you will learn how to implement very fast Image blur in C# using direct bit manipulation in pure .NET without the need for unsafe code.

Introduction

There's a C# example on Stack Overflow on how to do an image blur (you can find it here). It seems to be the best example on how to do this in C# available, but there are a couple of issues with it: It's slow, and it uses unsafe code.

I spent a little time with it, doing quite a bit of refactoring and converting it from unsafe to vanilla C#, and also rewriting it to use direct bit manipulation using a managed pointer to the bitmap's underlying array. This resulted in very fast (much faster than unsafe code) image processing.

Background

I stumbled across this Codeproject article on Fast pointerless image processing years ago. Mr Dunlap had a great way of directly accessing bitmap bits, but I hadn't seen anyone else on Codeproject doing anything with it. The code in this project is based on his idea.

Using the Code

Using the blur function is simple; Just call it as seen below:

C#
ImageTools.Blur(ref yourBitmap, intBlurSide);

The rewritten blur function looks like this:

C#
private static void Blur(ref Bitmap image, Rectangle rectangle, Int32 blurSize) {
            ExposedBitmap blurred = new ExposedBitmap(ref image);

            // Store height & width locally (improves performance)
            int height = blurred.Height;
            int width  = blurred.Width;

            for (int xx = rectangle.X; xx < rectangle.X + rectangle.Width; xx++)
            {
                for (int yy = rectangle.Y; yy < rectangle.Y + rectangle.Height; yy++)
                {
                    //byte red, green, blue;
                    int avgR = 0, avgG = 0, avgB = 0;
                    int blurPixelCount = 0;
                    int horizontalLocation;
                    int verticalLocation;
                    int pixelPointer;

                    // Average the color of the red, 
                    // green and blue for each pixel in the
                    // blur size while making sure 
                    // you don't go outside the image bounds:
                    for (int x = xx; (x < xx + blurSize && x < width); x++)
                    {
                        horizontalLocation = x * blurred.bytesPerPixel;
                        for (int y = yy; (y < yy + blurSize && y < height); y++)
                        {
                            verticalLocation = y * blurred.stride;
                            pixelPointer = verticalLocation + horizontalLocation;

                            avgB += blurred.pinnedArray.bytes[pixelPointer];
                            avgG += blurred.pinnedArray.bytes[pixelPointer + 1];
                            avgR += blurred.pinnedArray.bytes[pixelPointer + 2];

                            blurPixelCount++;
                        }
                    }

                    byte bavgr = (byte)(avgR / blurPixelCount);
                    byte bavgg = (byte)(avgG / blurPixelCount);
                    byte bavgb = (byte)(avgB / blurPixelCount);

                    // Now that we know the average for the blur size, 
                    // set each pixel to that color
                    for (int x = xx; x < xx + blurSize && x < width && 
                             x < rectangle.Width; x++)
                    {
                        horizontalLocation = x * blurred.bytesPerPixel;
                        for (int y = yy; y < yy + blurSize && 
                                 y < height && y < rectangle.Height; y++)
                        {
                            verticalLocation = y * blurred.stride;
                            pixelPointer = verticalLocation + horizontalLocation;

                            blurred.pinnedArray.bytes[pixelPointer]     = bavgb;
                            blurred.pinnedArray.bytes[pixelPointer + 1] = bavgg;
                            blurred.pinnedArray.bytes[pixelPointer + 2] = bavgr;
                        }
                    }
                }
            }

            image = blurred.exBitmap;
        }

My intention is for interested parties to download the project and have a look at the code itself.

History

  • 17th April, 2023: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
President Doxtader Industries LLC
United States United States
I've been in IT for the last 25 years in one capacity or another - always as either a network engineer or a developer... or both. At the moment I have an IT consultancy in Long Island, NY offering software development and network engineer services.

Comments and Discussions

 
BugExposedBitmap class constructor - "Stride" parameter bug in Bitmap constructor Pin
Member 1619395427-Feb-24 0:18
Member 1619395427-Feb-24 0:18 
GeneralRe: ExposedBitmap class constructor - "Stride" parameter bug in Bitmap constructor Pin
pdoxtader5-Mar-24 6:45
professionalpdoxtader5-Mar-24 6:45 
GeneralMy vote of 5 Pin
tbayart1-May-23 13:19
professionaltbayart1-May-23 13:19 
SuggestionNo Gaussian blur Pin
Lutz Hamann26-Apr-23 23:02
Lutz Hamann26-Apr-23 23:02 
GeneralRe: No Gaussian blur Pin
pdoxtader27-Apr-23 9:13
professionalpdoxtader27-Apr-23 9:13 
QuestionBroken Image Pin
Graeme_Grant19-Apr-23 9:33
mvaGraeme_Grant19-Apr-23 9:33 
AnswerRe: Broken Image Pin
pdoxtader19-Apr-23 10:16
professionalpdoxtader19-Apr-23 10:16 
QuestionA different way Pin
Kenneth Haugland17-Apr-23 18:37
mvaKenneth Haugland17-Apr-23 18:37 
AnswerRe: A different way Pin
pdoxtader17-Apr-23 18:54
professionalpdoxtader17-Apr-23 18:54 
GeneralRe: A different way Pin
Kenneth Haugland17-Apr-23 23:03
mvaKenneth Haugland17-Apr-23 23:03 
GeneralRe: A different way Pin
pdoxtader18-Apr-23 3:42
professionalpdoxtader18-Apr-23 3:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.