2010-03-31 17 views
1

Je crée une petite application où les enfants peuvent remplir des illustrations prédéfinies avec des couleurs. J'ai implémenté avec succès un seau de peinture de style MS-paint en utilisant l'argorithme de remplissage flood. Cependant, à proximité des bords des éléments d'image, les pixels restent non remplis, car les lignes sont anti-aliasées. Cela est dû au fait que la condition actuelle de remplissage est colourAtCurrentPixel == colourToReplace, ce qui ne fonctionne pas sur les pixels mélangés sur les lignes. (les couleurs sont des couleurs RVB)Remplissage de seau de peinture souple: Égalité des couleurs

Je voudrais ajouter une option de lissage/treshold comme dans Photoshop et d'autres outils sophistiqués, mais quel est l'algorithme pour déterminer l'égalité/la distance entre deux couleurs?

if (match(pixel(x,y), colourToReplace) setpixel(x,y,colourToReplaceWith)

Comment remplir match()?

Ici, une image (est: gauche, droite est voulu)

alt text http://www.freeimagehosting.net/uploads/6aa7b4ad53.png

Voici mon code complet actuel:

  var b:BitmapData = settings.background; 
      b.lock(); 

      var from:uint = b.getPixel(x,y); 


      var q:Array = []; 


      var xx:int; 
      var yy:int; 
      var w:int = b.width; 
      var h:int = b.height; 
      q.push(y*w + x); 
      while (q.length != 0) { 
       var xy:int = q.shift(); 
       xx = xy % w; 
       yy = (xy - xx)/w; 
       if (b.getPixel(xx,yy) == from) { //<- want to replace this line 
        b.setPixel(xx,yy,to); 
        if (xx != 0) q.push(xy-1); 
        if (xx != w-1) q.push(xy+1); 
        if (yy != 0) q.push(xy-w); 
        if (yy != h-1) q.push(xy+w); 
       } 
      } 
      b.unlock(null); 

Répondre

1
bien

, je suppose que l'approche la plus naturelle est de calculer la différence entre les couleurs. pour atteindre une valeur raisonnable, il faut calculer la différence par canal. ont pas testé, mais devrait fonctionner:

const perChanThreshold:uint = 5; 
const overallThreshold:uint = perChanThreshold * perChanThreshold * 3; 
function match(source:uint, target:uint):Boolean { 
    var diff:uint = 0, chanDiff:uint; 
    for (var i:int = 0; i < 3; i++) { 
     chanDiff = (source >> (i * 8)) & 0xFF; 
     diff += chanDiff * chanDiff; 
    } 
    return diff <= overallThreshold; 
} 
+1

Merci, je fais quelque chose comme ça maintenant. Voir ma réponse –

1

Fait quelque chose qui fonctionne:

   c = b.getPixel(xx,yy); 
       if (c == to) continue; 
       if (c != from) d = 
        Math.pow(f1 - (c & 0xFF), 2) + 
        Math.pow(f2 - (c >> 8 & 0xFF), 2) + 
        Math.pow(f3 - (c >> 16 & 0xFF), 2) 
       if (c == from || d < tres) { 
+1

oui, devrait fonctionner parfaitement. cependant s'il vous plaît noter, que cela ne fonctionnera pas très bien si vous l'appelez souvent (ce qui peut être le cas pour un remplissage). Aller et venir entre les flottants et les entiers n'est pas très rapide, les appels de fonctions statiques non plus. – back2dos