将图像转换为可变数量的灰度

时间:2016-06-26 15:36:38

标签: javascript css svg svg-filters

我想将图像转换为可变数量的灰度,这个数字可由用户配置,范围从2(单色/黑白)到256(全灰度)。

我试图用css和svg过滤器完成此操作,例如在CSS中:

CREATE TABLE IF NOT EXISTS `wp_rdp_category_images` (
  `id` int(12) NOT NULL AUTO_INCREMENT,
  `category_name` varchar(32) NOT NULL,
  `category_image` varchar(64) NOT NULL,
   PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=22 ;

INSERT INTO `wp_rdp_category_images` (`id`, `category_name`, `category_image`) VALUES
(1, 'natuur', 'natuur1.jpg'),
(2, 'natuur', 'natuur4.jpg'),
(4, 'aarde', 'aarde3.jpg'),
(5, 'sport', 'sport2.jpg'),
(6, 'aarde', 'aarde3.jpg'),
(7, 'auto', 'autogrijs.jpg'),
(8, 'auto', 'autowit.jpg'),
(9, 'auto', 'autoblack.jpg'),
(10, 'auto', 'autoroodzwart.jpg'),
(11, 'aarde', 'aarde1.jpg'),
(12, 'aarde', 'aarde2.jpg'),
(13, 'sport', 'sport4.jpg'),
(14, 'sport', 'sport3.jpg'),
(15, 'sport', 'sport1.jpg'),
(16, 'natuur', 'natuur2.jpg'),
(17, 'natuur', 'natuur3.jpg'),
(18, 'people', 'people1.jpg'),
(19, 'people', 'people2.jpg'),
(20, 'people', 'people3.jpg'),
(21, 'people', 'people4.jpg'); 

将图像转换为灰度,这就是我想要的256灰度,但其他值如

filter: grayscale(100%)

不限制灰度的数量,但只减少图片中使用的颜色数量,因此我永远无法使用这些滤镜获得单色效果。

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

我建议:

  1. <image><svg>绘制到画布
  2. 通过组合由视觉上吸引人的因素加权的每个颜色通道
  3. ,将画布图像数据缩小为灰度
  4. 通过在[0, 255/(n-1), 255/(n-2), ..., 255]
  5. 中四舍五入到最接近的颜色来减少颜色数量
  6. 如果需要,将画布图像数据写回<image>
  7. 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">

    此算法速度非常快,但如果原始图像中没有颜色落入指定的颜色范围之一,则生成的图像可能会少于指定的颜色数。在这种情况下,您需要more advanced color quantization algorithm such as median cut

    根据您的需要,将调整大小的侦听器附加到<svg>并使用相应尺寸的画布元素动态覆盖它,以显示生成的灰度图像。

    样本图片:

    Sample picture

答案 1 :(得分:2)

您可以使用SVG过滤器执行此操作,但在Internet Explorer中限制为最多64个值。直黑/白色的过滤器是这样的:

<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>

十值灰度的过滤器将是:

<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>

在输入更改时,使用JavaScript在适当数量的范围内写入。