3

さて、私はアプリケーションを作成しています.forループを使用して、基本的に画像のすべてのピクセルを読み取り、ピクセルカラーのパターンを探しています(単純なもの)とにかく、何らかの理由でアプリケーションが単にロックされ、通常に戻ることはありません. 実際の問題は見られずに、コードを何度もループしました。

私が気付いた唯一のことは、ScanPixelsLater の for ループが早期に終了する可能性があることです。可能な限りコードにコメントしましたが、

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++;
                DetectNextWhiteLine(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

}
4

2 に答える 2

2

したがって、アプリケーションがハングする理由を理解するには、WinForm アプリケーションがどのように機能するかについて少し知る必要があります。

UI が実行されているスレッドには、メッセージ ポンプと呼ばれるものもあります。このメッセージ ポンプには、オペレーティング システム (およびその他のソース) からすべての UI 要素に渡されるメッセージが含まれています。いつ状態を変更するか、いつ自分自身を再描画するかなどを伝えます。あなたのような長時間実行ループがある場合、メッセージポンプはメッセージを処理できません。get はキューに入れられましたが、処理されませんでした。これは、アプリケーションが「ハング」することを意味します。

アプリケーションが回復しない可能性はほとんどありません。ループは最終的に終了し、UI は再び応答するようになります (どこかで無限ループを見逃していないと仮定しますが、そうではないと思います)。ただし、GDI+ の GetPixel メソッドは非常に低速であり、イメージが大きい場合、一連のループが完了するまでに長い時間がかかります。おそらく、安全でないコンテキストを詳しく調べて、LockBits を使用してイメージのメモリへのポインターを取得する必要があります。ここに浮かぶ方法の多くの例があります。

編集: コードをもう少し詳しく見てみると、比較的非効率的であることも明らかです。少なくとも 6 レベルのネストされた for ループが実行されているため、1 回のスキャンのみが必要な場合でも、基本的にイメージを複数回スキャンしています。

画像処理は、リソースを大量に消費するプロセスです。パフォーマンスを重視するすべての作業をできるだけ効率的に行うように注意する必要があります。

于 2011-01-22T20:46:15.820 に答える
2

私のコメントから移行されました (現在は削除されています)

正常にならないため、問題を引き起こすのはこれではありませんが、決してGetPixelループを呼び出すべきではありません。それを使用するのは信じられないほど遅いです。代わりに、ポインターまたはピクセル配列を使用できます。google または stackoverflow で「getpixel slow」を検索すると、多数のソリューションが表示されます。

更新:コードを少し調べました... ネストされた for ループであるメイン コード ( ScanPixels) では、DetectNextWhiteLineこれもネストされた for ループであり、最後にこれがScanPixelsLaterネストされた for-ループ。これで、比較的高価なメソッド ( ) を呼び出す 6 レベルの深さの for ループ O(n^6) がネストされている可能性がありますGetPixel。ピクセルを数回だけ反復する必要があります。これは、1000^6*~100 命令のような潜在的なものであるため、停止しない理由かもしれません:)

于 2011-01-22T20:46:32.830 に答える