2017-07-02 5 views
0

ich als Bildercontext.putImageData von HTML <canvas> setzt auf falsche Koordinaten

enter image description here

als Bild zeigt jede durchschnittliche Farbe von 100 Rechteck zu bekommen versuchen, die geklebt imagedata nicht geeignet eingestellt. Aber das alle Koordinatenparameter (ctx.getImageData() und ctx.putImageData()) ist die gleiche wie console.log Bild im Anhang I

enter image description here

Ist es Fehler? Oder habe ich etwas vermisst?

convert(){ 
    let canvas = this.$el.querySelector('#pixel-art-canvas'), 
     image = this.$el.querySelector('#upload-image'), 
     ctx = canvas.getContext('2d'), 
     degree = 10, 
     img = new Image, 
     tiles = Math.pow(degree,2), 
     eachWidth,eachHeight; 

    img.src = image.src; 
    ctx.drawImage(img,0,0); 

    eachWidth= canvas.width/degree; 
    eachHeight= canvas.height/degree; 

    for(let k = 0; k < tiles; k++) { 
    let imgd,x,y, 
     rgb = {r:0,g:0,b:0}, 
     count = 0; 

    x = (k % degree) * eachWidth; 
    y = (k/degree) * eachHeight; 
    imgd = ctx.getImageData(x, y, eachWidth, eachHeight); 
    console.log('x: ' + x + ' , y:' +y+' , w: '+eachWidth + ' , h :' +eachHeight); 

    for (let i=0; i < imgd.data.length; i=i+4) { 
     rgb.r += imgd.data[i]; 
     rgb.g += imgd.data[i+1]; 
     rgb.b += imgd.data[i+2]; 
     count++; 
    } 

     rgb.r = ~~(rgb.r/count); 
     rgb.g = ~~(rgb.g/count); 
     rgb.b = ~~(rgb.b/count); 

    for (let j=0; j < imgd.data.length; j=j+4) { 
      imgd.data[j] = rgb.r; 
      imgd.data[j+1] = rgb.g; 
      imgd.data[j+2] = rgb.b; 
     } 

    ctx.putImageData(imgd, x, y, 0, 0, eachWidth, eachHeight); 
    console.log('x: ' + x + ' , y:' +y+' , w: '+eachWidth + ' , h :' +eachHeight); 
    }//end for 

} 

Antwort

0

Das Problem ist, dass Sie die y-Koordinate falsch berechnen.

Sie haben

y = (k/degree) * eachHeight; 

, die ein Bruchergebnis für (k/Grad) geben Sie abzuzurunden müssen (Boden) den Wert, bevor es zu multiplizieren.

// to fix the y coord. 
y = Math.floor(k/degree) * eachHeight; 
// or 
y = ((k/degree) | 0) * eachHeight; 

Auch Sie erhalten falsch den Mittelwert der Farben. RGB-Werte repräsentieren die Quadratwurzel der Intensität des Pixels. Daher ist der Intensitätsunterschied zwischen einem RGB-Wert von 128 und 256 nicht 2 mal, sondern 4 mal so hell.

Wenn Sie den Mittelwert nehmen, indem Sie nur die RGB-Werte summieren, erhalten Sie ein Ergebnis, das dunkler ist, als es sein sollte.

Die korrekte Methode besteht darin, den Mittelwert des Quadrats der RGB-Werte zu erhalten, und dann zurück in logarithmisches RGB zu konvertieren, um es wieder auf die Leinwand zu setzen.

Ändern Sie Code

const rgb = {r:0,g:0,b:0}; 
var count = 0; 

for (let i=0; i < imgd.data.length; i=i+4) { 
    rgb.r += imgd.data[i] * imgd.data[i]; // Square the value 
    rgb.g += imgd.data[i + 1] * imgd.data[i + 1]; 
    rgb.b += imgd.data[i + 2] * imgd.data[i + 1]; 
    count++; 
} 
// Get mean and convert back to logarithmic 
// Also you do not need to floor the values with ~~(val) as 
// the array is of type Uint8ClampedArray which will floor and clamp the 
// values for you. 
// Also ~~(val) requires 2 operations, a quicker way the requires only one 
// operation is (val) | 0 
rgb.r = Math.sqrt(rgb.r/count); 
rgb.g = Math.sqrt(rgb.g/count); 
rgb.b = Math.sqrt(rgb.b/count); 

for (let j=0; j < imgd.data.length; j=j+4) { 
     imgd.data[j] = rgb.r; 
     imgd.data[j+1] = rgb.g; 
     imgd.data[j+2] = rgb.b; 
    } 

ctx.putImageData(imgd, x, y, 0, 0, eachWidth, eachHeight); 

Sie auch ein wenig über optimieren können.

const x = (k % degree) * eachWidth; 
const y = ((k/degree) | 0) * eachHeight; 
const imgd = ctx.getImageData(x, y, eachWidth, eachHeight); 
const rgb = {r : 0, g : 0, b : 0}; 
const count = imgd.data.length/4; 
var i = 0; 
while(i < imgd.data.length) { 
    rgb.r += imgd.data[i] * imgd.data[i++]; // square the value 
    rgb.g += imgd.data[i] * imgd.data[i++]; 
    rgb.b += imgd.data[i] * imgd.data[i++]; 
    i ++; 
} 
// need to round as we are not directly adding back to the buffer. 
rgb.r = Math.sqrt(rgb.r/count) | 0; 
rgb.g = Math.sqrt(rgb.g/count) | 0; 
rgb.b = Math.sqrt(rgb.b/count) | 0; 

// get a refer to 32 bit version of same data and set all values 
// the 0xFF000000 sets the alpha to 255 
// shift red 2 bytes (16 bits) 
// shift green 1 byte (8 bit) 
// blue is in the correct place. 
new Uint32Array(imgd.data.buffer).fill(
    0xFF000000 + (rgb.r << 16) + (rgb.g << 8) + rgb.b 
); 

// putImageData use 3 arguments imgd and the x, y if you are 
// copying all the data back to the canvas. 
ctx.putImageData(imgd, x, y); 
+0

Wow .. Ich kann nicht glauben, Ihr tiefes Verständnis von all dem ... großer Programmierer Sie sind –

Verwandte Themen