Solved

Faster Imaging Processing Width and Level in C#

Posted on 2007-04-03
4
374 Views
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;
            unsafe
            {
                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;
                        }
                        else
                        {
                            if (ImgWidth == 0)
                            {
                                color = 0;
                            }
                            else
                            {
                                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;
                }
            }
            bm.UnlockBits(bmData);
            bm.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipX);
            Backimage = bm;
0
Comment
Question by:raw_enha
  • 2
4 Comments
 
LVL 22

Assisted Solution

by:_TAD_
_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.
0
 
LVL 48

Expert Comment

by:AlexFM
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?
0
 
LVL 48

Accepted Solution

by:
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.
0
 
LVL 5

Assisted Solution

by:ennixo
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.

0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
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. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Hi friends,  in this video  I'll show you how new windows 10 user can learn the using of windows 10. Thank you.

867 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now