【问题标题】:How to filter a specific color from a bitmapData object (or byte-array)如何从 bitmapData 对象(或字节数组)中过滤特定颜色
【发布时间】:2011-03-06 17:18:04
【问题描述】:

我正在寻找一种从 ActionScript 3 中的 bitmapData 对象过滤特定颜色的有效方法。目前我使用带有 readByte32() 的循环。这需要大约一秒钟的时间来处理,这是不可接受的。我一直在尝试让 paletteMap() 工作,但到目前为止还不能掌握它的 API(任何真正有用的链接?谷歌让我失望了......)。

这是我目前想要改进的逻辑:

var n:int = bitmapData.width;
for (var i:int = 0; i < n; i++) {
 var m:int = bitmapData.height;
 for (var j:int = 0; j < m; j++) {
  var color:int = bitmapData.getPixel(i, j);
  if (color == 0xCACACA) {
   bitmapData.setPixel32(i, j, 0x00000000);
  }
 }
}

我可以通过使用 Vectors 获得更好的性能,但只是稍微好一点...

var v:Vector.<uint> = bitmapData.getVector(bitmapData.rect);
var n:int = bitmapData.width * bitmapData.height;
for (var i:int = 0; i < n; i++) {
 var color:uint = v[i];
 v[i] = color == 0xFFCACACA ? 0x00000000 : color;
}
bitmapData.setVector(bitmapData.rect, v);

我真的认为必须有更好的方法来做到这一点,只需要 100 毫秒。如果有人能为我解开bitmapData的奥秘,你就是我族人的新领袖。

PS 我正在使用 bitmapData.lock() 和 unlock();我只是没有发布样板文件。

【问题讨论】:

    标签: actionscript-3 bitmap bitmapdata palette getpixel


    【解决方案1】:

    一个简单的方法是使用threshold 方法。一开始有点麻烦,但很快(我想你会很快)

    这会将每个红色像素(仅考虑红色像素,其值恰好为 0xffff0000)变为蓝色 (0xff0000ff)。

    var colorToReplace:uint = 0xffff0000;
    var newColor:uint = 0xff0000ff;
    var maskToUse:uint = 0xffffffff;
    
    var rect:Rectangle = new Rectangle(0,0,bitmapData.width,bitmapData.height);
    var p:Point = new Point(0,0);
    bitmapData.threshold(bitmapData, rect, p, "==", colorToReplace, 
            newColor, maskToUse, true);
    

    【讨论】:

    • 谢谢,让我试试这个并比较性能。我会回复你的。
    • 太棒了。使用 threshold() 比我上面的尝试快 100 倍以上。我不敢相信这么复杂的方法能这么快奏效。非常感谢!
    • @jpwrunyan。没问题。 threshold 在这里所做的几乎和你的代码一样,我想。但是,最大的区别在于它是本地运行的。这将永远击败任何 Actionscript。根据经验,每当您看到一堆 setPixel / getPixel 调用时,尤其是在紧密循环中,请尝试找到一种方法将它们替换为原生等效项。如果这不可能,像素弯曲器可能会有所帮助,但它不会像本机代码那样快。
    【解决方案2】:

    Flash 有一个类似于着色器的 API,称为 pixel bender,在这种情况下可能对您有用。这是adobe关于如何apply a pixel bender filter to an image in flash的教程。

    否则,您可以一次处理行。 (请注意,您的代码中的一个小错误是在每次宽度迭代时重新获取高度):

    private var currentRow:Number = 0;
    private var timer:Timer;
    public function processImage(event:Event=null):void
    {
        var m:int = bitmapData.height;
        for (var j:int = 0; j < m; j++)
        {
            if (bitmapData.getPixel(currentRow, j) == 0xCACACA)
            {
                bitmapData.setPixel32(currentRow, j, 0x00000000);
            }
        }
    
        currentRow++;
        if(currentRow < bitmapData.width)
        {
            timer = new Timer(1, 500);
            timer.addEventListener(TimerEvent.COMPLETE, processImage);
            timer.start();
        }
    }
    

    处理时间会长一些,但至少你的显示不会被阻塞。

    【讨论】:

    • 感谢您指出第一个双循环版本的错误!但是,我不确定您为什么要使用上面的 Timer。我不是动画效果。我只是在处理一个图像,必须从图像中删除一个非常特定的颜色(用 0x00000000 替换它)。
    猜你喜欢
    • 2020-02-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多