2016-06-26 18 views
2

Ich möchte ein Bild in eine variable Anzahl von Graustufen umwandeln, die vom Benutzer konfigurierbar ist und von 2 (monochrom/schwarz/weiß) bis 256 (volle Graustufen) reicht. .Bild in variable Anzahl von Graustufen umwandeln

Ich habe versucht, dies mit css und SVG-Filter, z. in CSS:

filter: grayscale(100%) 

wandelt ein Bild zu Graustufen, das ist, was ich für 256 Graustufen wollen würde, aber andere Werte wie

filter: grayscale(10%) 

Sie die Anzahl der Graustufen nicht begrenzen, sondern reduzieren nur die Zahl von Farben, die im Bild verwendet werden, so kann ich mit diesen Filtern niemals ein monochromes Ergebnis erhalten.

Danke für Ihre Hilfe.

+0

Sie können das Bild zuerst erhalten und dann auf eine Leinwand zeichnen und nacheinander auf die RGB-Werte der Pixel zugreifen. Dann wird Y (Luminanz) mit der Formel "Y = 0,299 * R + 0,587 * G + 0,114 * B" berechnet und das berechnete Y zurück in die Orte von R, G und B pro Pixel eingefügt. – Redu

+0

Für zukünftige Referenz wird diese Technik, die Sie versuchen zu erreichen, "Quantisierung" genannt, wie in der Antwort unten beschrieben. –

Antwort

2

Sie können dies ein SVG-Filter, aber Sie sind auf maximal 64 Werte im Internet Explorer beschränkt. Der Filter für einen gerade schwarz/weiß posterize ist dies:

<filter id="greyscale-posterize" color-interpolation-filters="sRGB"> 
<feColorMatrix type="saturate" values="0"/> 
<feComponentTransfer> 
    <feFuncR type="discrete" tableValues="0 1"/> 
    <feFuncG type="discrete" tableValues="0 1"/> 
    <feFuncB type="discrete" tableValues="0 1"/> 
</feComponentTransfer> 
</filter> 

Der Filter für zehn Wert Graustufen- wäre:

<filter id="greyscale-posterize" color-interpolation-filters="sRGB"> 
<feColorMatrix type="saturate" values="0"/> 
<feComponentTransfer> 
    <feFuncR type="discrete" tableValues="0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1"/> 
    <feFuncG type="discrete" tableValues="0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1"/> 
    <feFuncB type="discrete" tableValues="0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1"/> 
</feComponentTransfer> 
</filter> 

verwendet JavaScript in der entsprechenden Anzahl von Bereichen zu schreiben, wie der Eingang geändert.

+0

Vielen Dank, das war die Art von Lösung, auf die ich gehofft hatte! Ich habe getan, wie Sie vorgeschlagen und die tableValues ​​mit JavaScript ändern, der Filter wird auf das Bild mit CSS angewendet. Das funktioniert einwandfrei in Chrome, tut aber nichts in Firefox. – dlkmp

+0

Ohne Ihren Code zu sehen, vermute ich, dass es ein Präfix-Problem ist. Firefox verwendet den nicht fixierten Filter (in Firefox gibt es keinen -moz-Filter). –

2

ich vorschlagen:

  1. die <image> oder <svg> auf eine Leinwand
  2. Zeichnung der Leinwand Bilddaten zu reduzieren, indem die Kombination jeden Farbkanal durch ein optisch ansprechender Faktor
  3. Verringerung der Anzahl von Farben zu gewichten Graustufen durch Abrunden auf die nächste Farbe in [0, 255/(n-1), 255/(n-2), ..., 255]
  4. Schreiben der Leinwandbilddaten zurück zu einem <image>, falls erforderlich.

function rgbaToNGrayscales(src, numScales) { 
 
    var d = (numScales - 1)/255, 
 
     inv_d = 1/d, 
 
     round = Math.round; 
 
    for (var i = 0; i < src.length; i += 4) { 
 
    src[i] = src[i + 1] = src[i + 2] = round(((src[i] * 4899 + src[i + 1] * 9617 + src[i + 2] * 1868 + 8192) >> 14) * d) * inv_d; 
 
    } 
 
} 
 

 
var source = document.getElementById("source"); 
 
var target = document.getElementById("target"); 
 
var slider = document.getElementById("slider"); 
 

 
slider.addEventListener("input", function(event) { 
 
    var canvas = document.createElement('canvas'), 
 
     context = canvas.getContext('2d'); 
 
    canvas.width = source.width; 
 
    canvas.height = source.height; 
 
    context.drawImage(source, 0, 0); 
 
    var imageData = context.getImageData(0, 0, canvas.width, canvas.height); 
 
    rgbaToNGrayscales(imageData.data, slider.value); 
 
    context.putImageData(imageData, 0, 0); 
 
    target.src = canvas.toDataURL(); 
 
});
<input id="slider" type="range" min="1" max="10" value="0"> 
 
<image id="source" crossOrigin="anonymous" src="http://cors.io?u=http://i.stack.imgur.com/kTjOI.png"> 
 
<image id="target">

Dieser Algorithmus ist sehr schnell, aber das resultierende Bild haben könnte weniger als die angegebene Anzahl von Farben, wenn es keine Farbe im Originalbild ist in einem der angegebenen Farbe fallen Bereiche. In diesem Fall benötigen Sie eine more advanced color quantization algorithm such as median cut.

Fügen Sie je nach Bedarf einen Größenänderungs-Listener an Ihre <svg> an und überlagern Sie ihn dynamisch mit einem Canvas-Element der entsprechenden Dimensionen, das das resultierende Graustufenbild anzeigt.

Das Beispielbild:

Sample picture

+0

Danke auch für Ihre Lösung. Ich hatte gehofft zu vermeiden, dass ich alles per Hand in JavaScript machen müsste, aber das ist wahrscheinlich die weniger Browser-abhängige Lösung. – dlkmp