开发者

For Loops, Application Hanging

Well I'm creating an application, I'm using for loops to basically read every pixel of an image looking for patterns in pixel color (simple stuff) Anyway for some reason my application simply locks up and never reverts back to normal. I've loop through the code time and time again without seeing any real problems.

The only thing I've noticed, is the for loop in ScanPixelsLater may be exiting early. I've commented the code as much as possible,

private Point topLeftc, bottomLeftc, topRightc, bottomRightc;

/// <summary>
/// Starts the initial looping process, designed only to loop through ONCE, ScanPixelsLater takes over
/// </summary>
/// <param name="img">Image to scan</param>
public void ScanPixels(Bitmap img)
{
    int whitePixel = 0;

    for (int y = 100; y < img.Height; y++)
    {

        for (int x = 100; x < img.Width; x++)
        {

            if (img.GetPixel(x, y) == Color.FromArgb(255, 255, 255, 255))
            {
                // img.SetPixel(x, y, Color.Green);
                whitePixel++;

            }
            else { whitePixel = 0; }


            if (whitePixel == 18)
            {
                whitePixel = 0;
                topLeftc = new Point(x - 18, y);
                DetectNextWhiteLine(topLeftc, img);

            }
        }
    }


}


/// <summary>
/// First creates the TopRight value via using the last pixel in x range, and using the current Y value
/// Then a Y loop is started 10 pixels down, within this loop is another X loop which scans the X range
/// If 10 consecutive white pixels are found, the TopLeft X value and the current Y value are used to map the 
/// BottomLeft and BottomRight coordinates. Finally a new Point is created which starts (x = 1) and (y = currentYValue + 2)
/// The ScanPixelsLater method is then called, passing the new Point (newLocation).
/// 
/// </summary>
/// <param name="p">The x and y value of where the pixels were found</param>
/// <param name="img">Image being used</param>
private void DetectNextWhiteLine(Point p, Bitmap img)
{

    int whitePixel = 0;
    topRightc = new Point(img.Width, topLeftc.Y);

    for (int y = p.Y + 10; y < img.Height; y++)
    {

        for (int x = p.X - 5; x < img.Width; x++)
        {
            if (img.GetPixel(x, y) == Color.FromArgb(255, 255, 255, 255))
            {
                whitePixel++;
            }
            else
            {
                whitePixel = 0;
            }

            if (whitePixel == 10)
            {
                bottomLeftc = new Point(topLeftc.X, y);
                bottomRightc = new Point(img.Width, y);
                Cords.Add(new Coordinates(topLeftc, topRightc, bottomLeftc, bottomRightc));

                Point newLocation = new Point(1, y + 2);
                calls++;
                ScanPixelsLater(newLocation, img); //rescan the image from new y axis 
            }
        }
    }

}



/// <summary>
/// Loops through the pixels based on the p parameter, if 15 white pixels are found, the location (x & y) is
/// passed to the DetectNextWhiteLine method which fixes the next line with a similar number of white pixels.
/// </summary>
/// <param name="p">The Point(x,y) at which to start scanning</param>
/// <param name="img"></param>
private void ScanPixelsLater(Point p, Bitmap img)
{

    int whitePixel = 0;

    for (int y = p.Y; y < img.Height; y++)
    {

        for (int x = p.X; x < img.Width; x++)
        {
            if (img.GetPixel(x, y) == Color.FromArgb(255, 255, 255, 255))
            {
                whitePixel++;
            }
            else
            {
                whitePixel = 0;
            }

            if (whitePixel == 15)
            {
                bottomLeftc = new Point(topLeftc.X, y);
                topLeftc = new Point(x - 15, y);
                calls++;
                De开发者_如何学编程tectNextWhiteLine(topLeftc, img);
            }

        }
    }

    // only want this to execute after all the pixels within the entire img have been read
    // possibly executing early.

    DrawWhiteLines(img);
    AppArgs aa = new AppArgs(true);
    Change(this, aa); // custom event handler, fired behind form to update GUI

}


So, to understand why your application is hanging you need to know a little bit about how WinForm applications work.

The thread that your UI is running on also has what is called a message pump. This message pump contains messages that get passed from the operating system (and other sources) to all of the UI elements. They tell them when to change state, when to redraw themselves, etc. When you have a long running loop like yours the message pump cannot process messages. The get queued up, but never processed, and this is what it means for an application to 'hang'.

It is unlikely that your application will never recover. Your loop will eventually end and your UI will become responsive again (assuming I didn't miss an infinite loop somewhere, but I don't think that I did). However, the GDI+ GetPixel method is really very slow, and if your image is large at all that set of loops is going to take a long time to complete. You will likely have to delve into an unsafe context and obtain a pointer to the image's memory using LockBits. There are many examples of how to do that floating around here.

EDIT: After looking at your code a bit more closely it is also apparent that it is relatively inefficient. You have at least 6 levels of nested for loops going on there, so you are essentially scanning the image multiple times when only a single scan is needed.

Image processing is a resource intensive process. You need to be careful to do all of your performance intensive work as efficiently as possible.


migrated from my comments (now deleted)

It is properly not this which causes you trouble since it never comes to normal but you should never call GetPixel in a loop. It is incredible slow to use that. Instead you can use pointers or an pixel array Search for "getpixel slow" with google or stackoverflow and a large number of solutions come up.

Updated: I have looked a little bit on the code now... In the main code (ScanPixels) which is a nested for-loop, you call DetectNextWhiteLine which is also a nested for-loop and finally this calls ScanPixelsLater which is ALSO a nested for-loop. Now you potentially got a 6-level-deep nested for loop O(n^6) which calls an relatively expensive method (GetPixel). You should only iterate over the pixels a few times. This may be why it never stops because this is potential something like 1000^6*~100 instructions :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜