Solved

Faster Imaging Processing Width and Level in C#

Posted on 2007-04-03
4
373 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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Check my code out(2) 1 35
Get String split 5 33
Calling stored proc in EDMX 11 19
Visual Studio editor? 1 18
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
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…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

747 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

8 Experts available now in Live!

Get 1:1 Help Now