2017-09-29 2 views
0

Ich habe folgende Leinwand, die viele kleine (15x15) blockiert hat:Filter anwenden Glättung auf einer Leinwand

enter image description here

Was einen Filter Ich versuche, ist das Hinzufügen zu tun, um die Grenzen zwischen den Boxen zu entfernen und das Bild ist etwas konsistenter, so dass die Rechtecke nicht zu offensichtlich und glatt sind. Mit welchem ​​Filter oder Algorithmus kann ich dieses Ziel erreichen?

Bitte beachten Sie, dass ich die Art und Weise, wie ich die Leinwand erstelle, nicht ändern kann und dass ich eine Reihe Rechtecke zeichnen muss, um die endgültige Form zu erhalten. Und entschuldigt, wenn die Frage nicht klar genug ist.

+0

Könnten Sie einige der Code teilen? Sind die Linien transparent? Warum können Sie die Zellengröße nicht größer definieren? – K3N

+0

@ K3N dies sind nur ein paar Rechtecke, die ich mit 'ctx.fillRect' Funktion erstellt habe und nein kann ich nicht. Diese sind die Ausgabe einer anderen Komponente und unmöglich zu ändern. –

+1

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter + https://developer.mozilla.org/en-US/docs/Web/CSS/filter#blur() – Prinzhorn

Antwort

2

Verwenden Sie getImageData, um die Daten sofort um ein beliebiges Pixel zu erhalten und sie auf einer temporären Leinwand zusammen zu schmelzen. Ende von drawImage auf der primären Leinwand.

var c = document.body.appendChild(document.createElement("canvas")); 
 
var size = c.width = c.height = 50; 
 
var tileSize = 5; 
 
var padding = 0; 
 
var ctx = c.getContext("2d"); 
 
c.style.width = c.style.height = "400px"; 
 
for (var x = 0; x < size; x += tileSize) { 
 
    for (var y = 0; y < size; y += tileSize) { 
 
    ctx.fillStyle = (Math.random() > 0.5 ? "#FF0000" : (Math.random() > 0.5 ? "#00FF00" : '#0000FF')); 
 
    ctx.fillRect(x + padding, y + padding, tileSize - padding, tileSize - padding); 
 
    } 
 
} 
 

 
function blur(canvas) { 
 
    var ctx = canvas.getContext("2d"); 
 
    var tempCanvas = canvas.cloneNode(); 
 
    var tempCTX = tempCanvas.getContext("2d"); 
 
    var divideBy = 9; 
 
    for (var x = 0; x < size; x += 1) { 
 
    for (var y = 0; y < size; y += 1) { 
 
     var data = ctx.getImageData(x - 1, y - 1, 3, 3).data; 
 
     var arr = [0, 0, 0, 1]; 
 
     for (var dataIndex = 0; dataIndex < data.length; dataIndex += 4) { 
 
     arr[0] += (data[dataIndex] === 0 ? 0 : data[dataIndex]/divideBy); 
 
     arr[1] += (data[dataIndex + 1] === 0 ? 0 : data[dataIndex + 1]/divideBy); 
 
     arr[2] += (data[dataIndex + 2] === 0 ? 0 : data[dataIndex + 2]/divideBy); 
 
     } 
 
     arr = arr.map(function(a) { 
 
     return Math.round(a); 
 
     }); 
 
     tempCTX.fillStyle = "rgba(" + (arr.join(',')) + ")"; 
 
     tempCTX.fillRect(x, y, 1, 1); 
 
    } 
 
    } 
 
    ctx.drawImage(tempCanvas, 0, 0); 
 
} 
 
//TEST 
 
var output = document.body.appendChild(document.createElement("p")); 
 
var step = 0; 
 

 
function blurStep() { 
 
    blur(c); 
 
    step++; 
 
    output.innerHTML = "Blur step: " + step; 
 
    if (step < 20) { 
 
    setTimeout(blurStep, 1000/60); 
 
    } 
 
} 
 
setTimeout(blurStep, 1000);

EDIT 1 - Kantensteuerung

Ein leichter bearbeiten, die die schwarzen Ränder entfernt, die erzeugt wird, wenn meine Funktion außerhalb der bestehenden Leinwand geht:

var output = document.body.appendChild(document.createElement("p")); 
 
var c = document.body.appendChild(document.createElement("canvas")); 
 
var size = c.width = c.height = 50; 
 
var tileSize = 5; 
 
var padding = 0; 
 
var ctx = c.getContext("2d"); 
 
c.style.width = c.style.height = "800px"; 
 
for (var x = 0; x < size; x += tileSize) { 
 
    for (var y = 0; y < size; y += tileSize) { 
 
    ctx.fillStyle = (Math.random() > 0.5 ? "#FF0000" : (Math.random() > 0.5 ? "#00FF00" : '#0000FF')); 
 
    ctx.fillRect(x + padding, y + padding, tileSize - padding, tileSize - padding); 
 
    } 
 
} 
 

 
function blur(canvas) { 
 
    var ctx = canvas.getContext("2d"); 
 
    var tempCanvas = canvas.cloneNode(); 
 
    var tempCTX = tempCanvas.getContext("2d"); 
 
    var divideBy = 9; 
 
    for (var x = 0; x < size; x += 1) { 
 
    for (var y = 0; y < size; y += 1) { 
 
     var X = (x >= 1 ? x - 1 : x); 
 
     var Y = (y >= 1 ? y - 1 : y); 
 
     var overflowX = size - X < 3; 
 
     var overflowY = size - Y < 3; 
 
     var data = ctx.getImageData(X, Y, 3, 3).data; 
 
     if (overflowX) { 
 
     var i = 8; 
 
     do { 
 
      data[i] = data[i - 4]; 
 
      data[i + 1] = data[i - 4 + 1]; 
 
      data[i + 2] = data[i - 4 + 2]; 
 
      i += 12; 
 
     } while (i <= 32); 
 
     } 
 
     if (overflowY) { 
 
     var i = 24; 
 
     do { 
 
      data[i] = data[i - 12]; 
 
      i++; 
 
     } while (i <= 32); 
 
     } 
 
     var arr = [0, 0, 0, 1]; 
 
     for (var dataIndex = 0; dataIndex < data.length; dataIndex += 4) { 
 
     arr[0] += (data[dataIndex] === 0 ? 0 : data[dataIndex]/divideBy); 
 
     arr[1] += (data[dataIndex + 1] === 0 ? 0 : data[dataIndex + 1]/divideBy); 
 
     arr[2] += (data[dataIndex + 2] === 0 ? 0 : data[dataIndex + 2]/divideBy); 
 
     } 
 
     arr = arr.map(function(a) { 
 
     return Math.round(a); 
 
     }); 
 
     tempCTX.fillStyle = "rgba(" + (arr.join(',')) + ")"; 
 
     tempCTX.fillRect(x, y, 1, 1); 
 
    } 
 
    } 
 
    ctx.drawImage(tempCanvas, 0, 0); 
 
} 
 
//TEST 
 
var step = 0; 
 
var steps = 20; 
 

 
function blurStep() { 
 
    blur(c); 
 
    step++; 
 
    output.innerHTML = "Blur step: " + step + "/" + steps; 
 
    if (step < steps) { 
 
    requestAnimationFrame(blurStep); 
 
    } 
 
} 
 
requestAnimationFrame(blurStep);

2

Tun Sie es eher für Spaß als echte Hilfe. Aber Sie können Grundidee, lesen Sie weiter :)

Bitmap erstellen, erhalten pure Farbfeld (zum Beispiel imageData), Breite des Bildes erhalten und multiplizieren Sie es mit 4 ([r, g, b, a] ist ein Pixel)()

Wenn Sie wollen - Sie können es ändern, indem Sie einige "put data" Schleifen und Multipy Richtung um 15 machen, um diese "blocky" Stil zu bekommen!

Dann - tun, was Sie wollen. Ich werde zum Beispiel Zweck tun:

const channelResolution = 4; // if you don't have somehow alpha channel - make it 3. 
const lineDistance = imageWidth * channelResolution; 
const imageData = [ /* your ImageData from canvas */]; 

const [r, g, b, a] = [0, 1, 2, 3]; // directions inside channels 
const [left, right, up, down] = [ 
    -channelResolution, 
    channelResolution, 
    -lineDistance, 
    lineDistance]; // directions inside pixels 

// return array of channel values in given directions 
const scan = (data, scanChannel, scanPixel, scanDirections) => { 
    const scanResult = []; 

    scanResult.push(data[scanPixel + scanChannel]); 
    return scanResult.concat(scanDirections.map(direction => { 
     return data[scanPixel + scanChannel + direction]; 
    })); 
}; 

// mixer filter 
const mixChannel = (array) => { 
    let sum = 0; 
    array.map(channel => sum+=channel); 
    return sum/(array.length + 1); 
}; 

// blur edge filter/shader 
const blurEdges =() => { 
    const resultData = clone(imageData); // (you can do json transformation) 
    for(let pointer = 0; pointer < imageData * channelResolution - channelResolution; pointer += channelResolution) { 
    const [red, green, blue, alpha] = [ 
     mixChannel(scan(imageData, r, pointer, [up, left, down, right])), 
     mixChannel(scan(imageData, g, pointer, [up, left, down, right])), 
     mixChannel(scan(imageData, b, pointer, [up, left, down, right])), 
     mixChannel(scan(imageData, a, pointer, [up, left, down, right])), 
    ]; 

    resultData[pointer + r] = red; 
    resultData[pointer + g] = green; 
    resultData[pointer + b] = blue; 
    resultData[pointer + a] = alpha; 
    } 
    return resultData; // or putImageData 
} 
1

Es gibt viele viele Möglichkeiten zu verwischen. Leider sind die meisten von ihnen falsch und führen zu Bildern, die dunkler als das Original sind. Eine Unschärfe sollte nicht hellsten verlieren

Ich habe den Code aus Emil S. Jørgensen und korrigiert die Mathematik verwendet, damit die Bildhelligkeit nicht beeinträchtigt wird, da das Bild unscharf ist.

Für jeden Kanal r, g, b Sie den Mittelwert des Quadrats jeden in der Nähe Pixel erhalten und die sqrt davon verwenden, um den neuen verschwommenen Pixel bei der

Also, wenn Sie 3 Pixel hatten (nur auf der Suche eingestellt roter Kanal, r1, r2, r3) jeweils im Bereich 0-255, um die mittlere Helligkeit zu erhalten, müssen Sie den logarithmischen Kanalwert in einen linearen Photonenzähler konvertieren. Holen Sie sich den Mittelwert und konvertieren zurück. Also meanR = Math.sqrt*((r1 * r1 + r2 * r2 + r3 * r3)/3); gleich für grün und blau. Nicht Alpha.

Der Code, den ich geändert ist ein bisschen wie ein Hack mir die wichtige Rolle es in einem Kommentar versuchen würde passen, aber passen würde nicht

Es ist leicht, den Unterschied zu sehen, so dass Sie ein nicht einmal brauchen Seite an Seite.

var c = document.body.appendChild(document.createElement("canvas")); 
 
var size = c.width = c.height = 50; 
 
var tileSize = 5; 
 
var padding = 0; 
 
var ctx = c.getContext("2d"); 
 
c.style.width = c.style.height = "400px"; 
 
for (var x = 0; x < size; x += tileSize) { 
 
    for (var y = 0; y < size; y += tileSize) { 
 
    ctx.fillStyle = (Math.random() > 0.5 ? "#FF0000" : (Math.random() > 0.5 ? "#00FF00" : '#0000FF')); 
 
    ctx.fillRect(x + padding, y + padding, tileSize - padding, tileSize - padding); 
 
    } 
 
} 
 

 
function blur(canvas) { 
 
    
 
    var r,g,b,i,c; 
 
    var s = (v)=>Math.sqrt(v);   // sqrt of a value 
 
    var a =() => d[i] * d[i++];  // sqrt pixel channel and step to next 
 
    var ctx = canvas.getContext("2d"); 
 
    var tempCanvas = canvas.cloneNode(); 
 
    var tempCTX = tempCanvas.getContext("2d"); 
 
    var divideBy = 9; 
 
    for (var x = 0; x < size; x += 1) { 
 
    for (var y = 0; y < size; y += 1) { 
 

 
     var d = ctx.getImageData(x - 1, y - 1, 3, 3).data; 
 
     //============================ 
 
     // Change start by BM67 
 
     //============================ 
 
     c = i = r = g = b = 0; 
 
     while(i < 36){ 
 
     if(d[i+3] !== 0){ r += a(); g += a(); b += a(); i ++; c++; } 
 
     else { i+= 4 } 
 
     } 
 
     tempCTX.fillStyle = `rgb(${s(r/c)|0},${s(g/c)|0},${s(b/c)|0})`; 
 
     //============================ 
 
     // End change by BM67 
 
     //============================ 
 
     tempCTX.fillRect(x, y, 1, 1); 
 
    } 
 
    } 
 
    ctx.drawImage(tempCanvas, 0, 0); 
 
} 
 
//TEST 
 
var output = document.body.appendChild(document.createElement("p")); 
 
var step = 0; 
 

 
function blurStep() { 
 
    blur(c); 
 
    step++; 
 
    output.innerHTML = "Blur step: " + step; 
 
    if (step < 20) { 
 
    setTimeout(blurStep, 1000/60); 
 
    } 
 
} 
 
setTimeout(blurStep, 1000);