Faster Imaging Processing Width and Level in C#

Posted on 2007-04-03
Last Modified: 2013-12-16
i got this block of code that adjust the width and level of a grayscale image.  
The problem is that it is extremely slow, can any expert give me any tips to make it faster?
I'm trying to make the process in real time.

Backimage is where I store the original image in the buffer.

int range1 = ImageInfoObj.MaxPixel;
            int range0 = ImageInfoObj.MinPixel;
            int[] pixels = ImageInfoObj.GetPixels();
            if (ImageInfoObj != null)
                ImgWidth += distX * (range1 - range0 + 1) / ImageDrwPanel.Width;
                ImgLevel -= distY * (range1 - range0 + 1) / ImageDrwPanel.Height;
                if (ImgWidth <= 0) ImgWidth = 0;
                if (ImgWidth > range1 - range0 + 1) ImgWidth = range1 - range0 + 1;
                if (ImgLevel < range0) ImgLevel = range0;
                if (ImgLevel > range1) ImgLevel = range1;

            System.Drawing.Bitmap bm = new System.Drawing.Bitmap(Backimage.Width, Backimage.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
            System.Drawing.Imaging.BitmapData bmData = bm.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
            int stride = bmData.Stride;
            System.IntPtr Scan0 = bmData.Scan0;
            int index = -1;
                byte* p = (byte*)(void*)Scan0;
                int nOffset = stride - bm.Width * 4;
                for (int y = 0; y < bm.Height; ++y)
                    for (int x = 0; x < bm.Width; ++x)
                        int color = pixels[++index];
                        if (color < (ImgLevel - ImgWidth / 2))
                            color = 0;
                        else if (color > (ImgLevel + ImgWidth / 2))
                            color = 255;
                            if (ImgWidth == 0)
                                color = 0;
                                color = 255 * (color - ImgLevel + ImgWidth / 2) / ImgWidth;
                        p[2] = (byte)color;
                        p[1] = (byte)color;
                        p[0] = (byte)color;
                        p[3] = (byte)255;

                        p += 4;
                    p += nOffset;
            Backimage = bm;
Question by:raw_enha
  • 2
LVL 22

Assisted Solution

_TAD_ earned 150 total points
ID: 18843747

A few things....

1) How much of your CPU is being used for this process?   If you aren't using 100% of your CPU, you can multithread this piece and have 1 thread convert the top half of the image and the second thread convert the bottom half (or have more threads).

2) Division is an expensive process.  I'm not sure how .Net optimizes its code, but on the cpu level multiplying by 0.5 is 20 times faster than dividing by 2.  .Net may do this conversion for you, but it's worth the small change just to test it out.

3) A switch statement is, in most cases, most efficient.  If/else blocks can approach the efficiency of a switch statement, but will never be faster than a switch.

4) I also see that you are doing the same calculation over and over and over again within the loop.  By the time you get into the loop, the ImgWidth is constant - don't divide by 2 for each itteration.  Create a new variable halfImgWidth and work with that value.
LVL 48

Expert Comment

ID: 18843833
1. Replace 32bppPArgb bitmap with true graylevel bitmap which has one byte per pixel.

2. int color = pixels[++index];
This requires calculating of pixel offset. Replace this with unsafe pointer which is incremented in every iteration.

3. Make some math optimizations. For example:

if (color < (ImgLevel - ImgWidth / 2))
ImgLevel - ImgWidth / 2 can be calculated once before loop. However, I beleive that JIT compiler optimizes this.

if (ImgWidth == 0)
Is this test really necessary?
LVL 48

Accepted Solution

AlexFM earned 200 total points
ID: 18843868
I think also that bm.RotateFlip takes significant time - test this with StopWatch class. Maybe you need to change algorithm by such way that it fills bitmap already with rotation.

Assisted Solution

ennixo earned 150 total points
ID: 18849582
THE thing to know before everything else is that Bitmap.Width and Bitmap.Height are very slow when you access it
store these values in additional variables like this :

int width = bm.Width;
int height = bm.Height;

and the use width and height instead of bm.Width and bm.Height, the result will be a lot faster !

and as the other said, pre-compute every value before the loop so that it is not computed at each iteration.
even a division by 2 has to be computed before the loop.

another thing, divisions by 2, 4, 8 , 16, etc. on integers can be avoided with >> 1, >> 2, >> 3, >> 4 etc. if you need to do it inside the loop
same for multiplications with << 1, << 2 etc.

yet another thing, you may create a lookup table.
as the value of color is between 0 and 255 included, precompute the values in a table byte[256] and then, inside your loop just find the value of the table using color as an index.

Last thing but you are good on this point, remember that the processor have cache and they store a part of the image table when you iterate.
it is faster to do for y = etc. and inside for x = etc. always do this when you can.


Featured Post

How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK ( for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA.…

860 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question