2010-06-22 4 views
4

Je cherche un moyen efficace de filtrer une couleur spécifique d'un objet bitmapData dans ActionScript 3. Actuellement, j'utilise une boucle avec readByte32(). Cela prend environ une seconde à traiter, ce qui est inacceptable. J'ai essayé de faire fonctionner paletteMap() mais jusqu'ici, je n'ai pas été en mesure de saisir son API (des liens vraiment utiles? Google m'a échoué ...).Comment filtrer une couleur spécifique d'un objet bitmapData (ou byte-array)

Voilà ma logique actuelle, que je veux améliorer:

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); 
    } 
} 
} 

je peux obtenir une performance légèrement meilleure de l'utilisation de vecteurs, mais il est seulement un peu mieux ...

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); 

Je pense vraiment là doit être une meilleure façon de faire cela qui ne prend que quelques centaines de millisecondes. Si quelqu'un peut débloquer les mystères de bitmapData pour moi, vous serez le nouveau chef de mon peuple. PS J'utilise bitmapData.lock() et unlock(); Je n'ai juste pas posté les trucs cool.

Répondre

4

Une méthode simple consiste à utiliser la méthode threshold. C'est un peu lourd au début, mais c'est assez rapide (aussi vite que vous le croirez, je pense)

Cela va changer chaque pixel rouge (en considérant le rouge seulement un pixel dont la valeur est exactement 0xffff0000) en bleu (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); 
+0

Merci, laissez-moi essayer ceci et comparer la performance. Je reviendrai vers toi. – user372950

+0

Juste incroyable. L'utilisation de threshold() est plus de 100 fois plus rapide que mes tentatives ci-dessus. Je ne peux pas croire qu'une méthode aussi compliquée fonctionne si vite. Merci beaucoup! – user372950

+1

@jpwrunyan. Aucun problème. 'threshold' fait ici presque la même chose que votre code, je pense. La grande différence, cependant, est qu'il fonctionne nativement; cela va toujours battre n'importe quel Actionscript. En règle générale, lorsque vous voyez un tas d'appels setPixel/getPixel, surtout dans une boucle serrée, essayez de trouver un moyen de les remplacer par un équivalent natif. Si ce n'est pas possible, pixel bender peut vous aider, mais ce ne sera pas aussi rapide que le code natif. –

1

Flash a une API pour un langage de type shader appelé pixel bender qui peut vous être utile dans ce cas. Voici un tutoriel d'Adobe sur la façon de apply a pixel bender filter to an image in flash.

Sinon, vous pouvez traiter des lignes à la fois. (Note une légère erreur dans votre code a été de nouveau obtenir la hauteur à chaque itération de la largeur):

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(); 
    } 
} 

Le traitement prendra un peu plus, mais au moins votre écran ne sera pas bloqué.

+0

Merci d'avoir signalé l'erreur sur la première version à double boucle! Cependant, je ne suis pas sûr de savoir pourquoi vous utilisez une minuterie. Je n'anime pas un effet. Je suis juste en train de traiter une image et je dois supprimer une couleur très spécifique de l'image (en la remplaçant par 0x00000000). – user372950

Questions connexes