Je travaille sur une application Web simple qui simplifie les couleurs d'une image téléchargée sur une palette de couleurs sélectionnée par l'utilisateur. Le script fonctionne, mais il faut très longtemps pour boucler à travers l'image entière (pour de grandes images, il est plus de quelques minutes), en changeant les pixels.
Initialement, j'écris à la toile elle-même, mais j'ai changé le code afin que des modifications soient apportées à un objet imagédata code> et que la toile n'est mise à jour à la fin du script. Cependant, cela n'a pas vraiment fait beaucoup de différence. P>
// User selects colours:
colours = [[255,45,0], [37,36,32], [110,110,105], [18,96,4]];
function colourDiff(colour1, colour2) {
difference = 0
difference += Math.abs(colour1[0] - colour2[0]);
difference += Math.abs(colour1[1] - colour2[1]);
difference += Math.abs(colour1[2] - colour2[2]);
return(difference);
}
function getPixel(imgData, index) {
return(imgData.data.slice(index*4, index*4+4));
}
function setPixel(imgData, index, pixelData) {
imgData.data.set(pixelData, index*4);
}
data = ctx.getImageData(0,0,canvas.width,canvas.height);
for(i=0; i<(canvas.width*canvas.height); i++) {
pixel = getPixel(data, i);
lowestDiff = 1024;
lowestColour = [0,0,0];
for(colour in colours) {
colour = colours[colour];
difference = colourDiff(colour, pixel);
if(lowestDiff < difference) {
continue;
}
lowestDiff = difference;
lowestColour = colour;
}
console.log(i);
setPixel(data, i, lowestColour);
}
ctx.putImageData(data, 0, 0);
3 Réponses :
Un problème ou une option d'amélioration est clairement votre fonction SLICE code>, qui créera un nouveau tableau à chaque appel, vous n'en avez pas besoin. Je changerais la boucle pour la boucle comme si:
Il n'est pas nécessaire de trancher la matrice chaque itération. (Alors que Niklas a déjà déclaré).
Je bouclerais sur la matrice de données au lieu de boucler sur les dimensions de la toile et modifiez directement le tableau. P>
for(let i = 0; i < data.length; i+=4) { // i+=4 to step over each r,g,b,a pixel let pixel = getPixel(data, i); ... setPixel(data, i, lowestColour); } function setPixel(data, i, colour) { data[i] = colour[0]; data[i+1] = colour[1]; data[i+2] = colour[2]; } function getPixel(data, i) { return [data[i], data[i+1], data[i+2]]; }
J'ajoute une réponse parce que vous avez un algorithme de correspondance de couleur très médiocre. P>
Trouver comment une couleur correspond à une autre est meilleure si vous imaginez chaque couleur unique possible. comme un point dans l'espace 3D. Les valeurs rouges, vertes et bleues représentent la coordonnée X, Y, Z. P>
Vous pouvez ensuite utiliser une géométrie de base pour localiser la distance d'une couleur à l'autre. P>
function convertBitmap(canvas, maxTime) { // maxTime in ms (1/1000 second) return new Promise(allDone => { const ctx = canvas.getContext("2d"); const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = pixels.data; var idx = data.length / 4; processPixels(); // start processing function processPixels() { const time = performance.now(); while (idx-- > 0) { if (idx % 1024) { // check time every 1024 pixels if (performance.now() - time > maxTime) { setTimeout(processPixels, 0); idx++; return; } } let i = idx * 4; const col = findClosest(data[i], data[i + 1], data[i + 2]); data[i++] = col[0]; data[i++] = col[1]; data[i] = col[2]; } ctx.putImageData(pixels, 0, 0); allDone("Pixels processed"); } }); } // process pixels in 10ms slices. convertBitmap(myCanvas, 10).then(mess => console.log(mess));