2017-09-23 1 views
0

J'essaie d'implémenter un algorithme de flou simple faisant la moyenne des couleurs des pixels environnants dans une zone 3x3.Le canevas de l'algorithme de flou ne fonctionne pas JS

boucle I throught la matrice de pixels, par incréments de 4. Ensuite, j'ai une fonction qui prend 6 paramètres:

r -> red value [0-255] int 
g -> green value [0-255] int 
b -> blue value [0-255] int 
a -> alpha value(opacity) [0-255] int 
d -> pixel array [r0,g0,b0,a0,r1,g1,b1,a1,r2... etc] array 
i -> current index 

Et je générons 4 nouvelle valeur, nouveau rouge, nouveau vert, nouveau bleu et nouvelles alpha et les renvoyer dans un objet.

Voici le code entier:

//canvas setup 
var width = 400; 
var height = 400; 

var canvas = document.querySelector('canvas'); 
var ctx = canvas.getContext('2d'); 

canvas.width = width; 
canvas.height = height; 

//create image 
var img = new Image(); 
img.src = 'images/input.jpg'; 

var pixels; 

img.onload = function(){ 
    ctx.drawImage(img, 0, 0); 
    pixels = ctx.getImageData(0, 0, width, height); 
} 

function action(pixels, callback){ 
    var newData = ctx.createImageData(width, height); 

    for(var i = 0; i < pixels.data.length; i+=4){ 
     var r = pixels.data[i]; 
     var g = pixels.data[i+1]; 
     var b = pixels.data[i+2]; 
     var a = pixels.data[i+3]; 

     var channels = callback(r, g, b, a, pixels.data, i); 

     newData.data[i] = channels.r; 
     newData.data[i+1] = channels.g; 
     newData.data[i+2] = channels.b; 
     newData.data[i+3] = channels.a; 

     pixels.data[i] = channels.r; 
     pixels.data[i+1] = channels.g; 
     pixels.data[i+2] = channels.b; 
     pixels.data[i+3] = channels.a; 
    } 

    ctx.putImageData(newData, 0, 0); 
} 

function run(){ 
    action(pixels, function(r,g,b,a,d,i){ 

     var nr = (r 
      + (d[i - 4] || r) 
      + (d[i + 4] || r) 
      + (d[i - 4 * width] || r) 
      + (d[i + 4 * width] || r) 
      + (d[i - 4 * width - 4] || r) 
      + (d[i + 4 * width + 4] || r) 
      + (d[i - 4 * width + 4] || r) 
      + (d[i + 4 * width - 4] || r) 
     )/9; 

     var ng = (g 
      + (d[i - 4] || g) 
      + (d[i + 4] || g) 
      + (d[i - 4 * width] || g) 
      + (d[i + 4 * width] || g) 
      + (d[i - 4 * width - 4] || g) 
      + (d[i + 4 * width + 4] || g) 
      + (d[i - 4 * width + 4] || g) 
      + (d[i + 4 * width - 4] || g) 
     )/9; 

     var nb = (b 
      + (d[i - 4] || b) 
      + (d[i + 4] || b) 
      + (d[i - 4 * width] || b) 
      + (d[i + 4 * width] || b) 
      + (d[i - 4 * width - 4] || b) 
      + (d[i + 4 * width + 4] || b) 
      + (d[i - 4 * width + 4] || b) 
      + (d[i + 4 * width - 4] || b) 
     )/9; 

     return {r: nr, g: ng, b: nb, a: 255}; 
    }); 
} 

Comme vous pouvez le voir, la valeur des pixels environnants sont codés en dur. Vous pouvez le tester ici:

https://codepen.io/tyrellrummage/pen/Ewgzzx

Si le bouton d'exécution ne fait rien, recharger et essayez à nouveau (une question avec la croix d'origine codepen). Essayez d'appuyer plusieurs fois sur le bouton Run pour augmenter les passes de l'algorithme.

Vous remarquerez que l'image sera complètement en niveaux de gris après 2/3 passes. Merci d'avance!

Répondre

0

Vous indexez les mauvais canaux dans le rappel. Et vous ne savez pas pourquoi vous faites ||

Ajoutez i++ après chaque canal de couleur dans le rappel.

De même, la valeur moyenne doit être la moyenne du carré de chaque valeur de canal car la valeur de chaque canal est la ~ sqrt de la luminosité. Ne pas équerrer les valeurs produira une moyenne plus sombre que ce qu'elle devrait être.

function run(){ 
    const w = width * 4; 
    // the offset index for each pixel excluding the center pixel 
    const grid = [-w - 4, -w, -w + 4, -4, 4, w - 4, w, w + 4]; 

    action(pixels,(r,g,b,a,dat,i) => { 
     var idx, count;   
     r *= r; 
     g *= g; 
     b *= b; 
     count = 1; 
     for(idx = 0; idx < grid.length; idx ++){ 
      const off = grid[idx]; 
      if(i + off >= 0 && i + off < w * height){ 
       r += dat[i + off] * dat[i + off]; 
       g += dat[i + 1 + off] * dat[i + 1 + off]; 
       b += dat[i + 2 + off] * dat[i + 2 + off]; 
       a += dat[i + 3 + off]; 
       count ++; 
      } 
     } 
     r = Math.sqrt(r/count); 
     g = Math.sqrt(g/count); 
     b = Math.sqrt(b/count); 
     a = a/count; 
     return {r,g,b,a}; 
    }); 
} 

déplacer BTW la ligne img.crossOrigin = "Anonymous"; dessus de la ligne que vous définissez la img.src que lorsque l'image est en cache, il se charge avant la ligne suivante et l'en-tête de anon ne soit pas joint à la demande.