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
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
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.…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor ( Top Charts is a view in which you can set seve…

628 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