0

アドビが提供するものは十分な柔軟性がないため、ActionScript3で独自の塗りつぶし関数を作成しようとしています(ターゲットカラーは1つしか指定できませんが、ターゲットカラーの範囲を指定したいと思います)。

だから、私がこれまでに思いついたひどいコードはこれです:

private function beginAlgortime(xx:int,yy:int):void
{
    if (bmp.bitmapData.getPixel(xx, yy) != 0x333333) {

        bmp.bitmapData.setPixel(xx, yy, 0x333333);

        beginAlgortime(xx + 1, yy);
        beginAlgortime(xx + 1, yy+1);
        beginAlgortime(xx + 1, yy - 1);

        beginAlgortime(xx , yy+1);
        beginAlgortime(xx , yy - 1);

        beginAlgortime(xx - 1, yy);
        beginAlgortime(xx - 1, yy+1);
        beginAlgortime(xx - 1, yy-1);
    }
}

かなり基本的な再帰関数..しかし、明らかにこの方法を使用すると、フラッシュプレーヤーは私をクラップスします:)誰かがこれに対する解決策を手に入れましたか?乾杯!

4

3 に答える 3

2

とにかく、垂直方向と水平方向の再帰がそれらのピクセルにヒットするため、対角線に直接再帰する必要はありません。

フラッドフィルとは正確には何を意味しますか?そして、「色の範囲」とはどういう意味ですか?

あなたが提供したルーチンは、ビットマップ全体を 0x333333 で埋めます。ビットマップの境界を離れるかどうかを確認しないため、終了しません。

于 2010-02-23T10:51:47.567 に答える
0

これは私が使用したものです:


private function floodFill(bitmapData: BitmapData, x: int, y: int, backColor: uint, fillColor: uint): void
{
    var data: Vector. = bitmapData.getVector(bitmapData.rect);

    var queueX:Vector. = new Vector.();
    var queueY:Vector. = new Vector.();

    queueX.push(x);
    queueY.push(y);

    while (queueX.length > 0) {
        x = queueX.shift();
        y = queueY.shift();

        if (x = width || y = height)
            return;

        if (data[y*width + x] == backColor) {
            data[y*width + x] = fillColor;

            queueX.push(x+1);
            queueY.push(y);

            queueX.push(x-1);
            queueY.push(y);

            queueX.push(x);
            queueY.push(y+1);

            queueX.push(x);
            queueY.push(y-1);
        }
    }

    bitmapData.setVector(bitmapData.rect, data);
}

于 2011-12-12T20:27:51.593 に答える
0

再帰関数から、プログラム スタックの代わりに配列を使用する反復関数に変換してみてください。

Allan が言及した記事で説明されているように、FloodFill の反復実装を次に示します。

function floodFill(bmpData:BitmapData, startX:int, startY:int, fill:uint, old:uint):void
{
    var queue:Array = new Array();

    queue.push(new Point(startX, startY));

    var iterations:uint = 0;
    var bmpWidth:int = bmpData.width;
    var bmpHeight:int = bmpData.height;

    var searchBmp:BitmapData = new BitmapData(bmpData.width, bmpData.height);
    var currPoint:Point, newPoint:Point;
    while (queue.length > 0)
    {
        currPoint = queue.shift();
        ++iterations;

        if (currPoint.x < 0 || currPoint.x >= bmpWidth) continue;
        if (currPoint.y < 0 || currPoint.y >= bmpHeight) continue;

        searchBmp.setPixel(currPoint.x, currPoint.y, 0x00);

        if (bmpData.getPixel(currPoint.x, currPoint.y) == old)
        {
            bmpData.setPixel(currPoint.x, currPoint.y, fill);

            if (searchBmp.getPixel(currPoint.x + 1, currPoint.y) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x + 1, currPoint.y));
            }
            if (searchBmp.getPixel(currPoint.x, currPoint.y + 1) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x, currPoint.y + 1));
            }
            if (searchBmp.getPixel(currPoint.x - 1, currPoint.y) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x - 1, currPoint.y));
            }
            if (searchBmp.getPixel(currPoint.x, currPoint.y - 1) == 0xFFFFFF)
            {
                queue.push(new Point(currPoint.x, currPoint.y - 1));
            }
        }

    }       
    trace("iterations: " + iterations);
}

編集:既に検索されたピクセルを追跡する方法をいくつか試した後、2 つ目の BitmapData インスタンスを使用すると非常にうまく機能することがわかりました。それに応じてコードを更新しました。

このコードは、私のコンピューターで 14 秒以内に 2000x1400 のビットマップを塗りつぶします。ユーザー エクスペリエンスを向上させるには、塗りつぶし処理を複数のフレームに分割して、ユーザーが待機中のアイコンを凝視する必要がないようにする必要があります。

ああ、これはまだ 1 つの色にしか影響しませんが、複数の色や色のしきい値などを使用するように簡単に変更できるはずです。

編集して追加:ウィキペディアのフラッド フィルの記事には、いくつかのアルゴリズムの提案があります。

于 2010-02-24T21:36:29.957 に答える