首页 > 解决方案 > 在 OpenLayers 5 中对 OSM 源使用光栅操作

问题描述

      var osmSource = new ol.source.OSM({
        transition: 0
      });
      var rasterSource = new ol.source.Raster({
          sources: [osmSource],
          operation: function(pixels,data) {
                var pixel = pixels[0];

                var r = pixel[0];
                var g = pixel[1];
                var b = pixel[2];

                // CIE luminance for the RGB
                var v = 0.2126 * r + 0.7152 * g + 0.0722 * b;

                pixel[0] = v; // Red
                pixel[1] = v; // Green
                pixel[2] = v; // Blue
                //pixel[3] = 255;

                return pixel;
            }
      });
      var mapLayer = new ol.layer.Image({
          source: rasterSource
      });

      var map = new ol.Map({
        layers: [mapLayer],
        target: 'map',
        view: new ol.View({
          center: [1331819, 7906244],
          zoom: 12
        })
      });
 <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

我正在尝试操纵从瓦片源(在本例中为 OSM)加载的瓦片中像素的颜色,并实现了一个简单的测试用例,并将其转换为灰度图,但对我来说它并没有真正起作用。

我已阅读 OpenLayers v5.3 的示例,以使用 Raster 源执行逐像素操作。

  var osmSource = new ol.source.OSM();
  var rasterSource = new ol.source.Raster({
      sources: [osmSource],
      operation: function(pixels,data) {
            var pixel = pixels[0];

            var r = pixel[0];
            var g = pixel[1];
            var b = pixel[2];

            // CIE luminance for the RGB
            var v = 0.2126 * r + 0.7152 * g + 0.0722 * b;

            pixel[0] = v; // Red
            pixel[1] = v; // Green
            pixel[2] = v; // Blue
            //pixel[3] = 255;

            return pixel;
        }
  });
  var mapLayer = new ol.layer.Image({
      source: rasterSource
  });

  var map = new ol.Map({
    layers: [mapLayer],
    target: 'map',
    view: new ol.View({
      center: [1331819, 7906244],
      zoom: 12
    })
  });

是的,我可以得到灰度图块,但有时它们似乎是中间版本之类的。有时加载的图块是完全白色的,有时介于白色和最终图像之间,当您放大时,有时您只是获得先前缩放级别的调整大小版本。

这是我的完整示例:

https://apertum.se/iairvirodvlp/maptest_grey.htm

标签: rasteroperationopenlayers-5

解决方案


我看不出您的演示有任何重大问题,但光栅操作会夸大缓慢加载 OSM 源的效果,这种情况在 OSM 切片服务器繁忙时经常发生。实现灰度的一种更有效的方法是在普通平铺层的后期合成事件中在画布上使用全局合成操作

osmLayer.on('postcompose', function (evt) {
    evt.context.globalCompositeOperation = 'color';
    evt.context.fillStyle = '#888';
    evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
    evt.context.globalCompositeOperation = 'source-over';
});

      var osmSource = new ol.source.OSM({
          transition: 0
      });
      var mapLayer = new ol.layer.Tile({
          source: osmSource
      });

      mapLayer.on('postcompose', function (evt) {
          evt.context.globalCompositeOperation = 'color';
          // check browser supports globalCompositeOperation
          if (evt.context.globalCompositeOperation == 'color') {
              evt.context.fillStyle = 'rgba(255,255,255,' + grayInput.value/100 + ')';
              evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
          }
          evt.context.globalCompositeOperation = 'overlay';
          // check browser supports globalCompositeOperation
          if (evt.context.globalCompositeOperation == 'overlay') {
              evt.context.fillStyle = 'rgb(' + [background,background,background].toString() + ')';
              evt.context.fillRect(0, 0, evt.context.canvas.width, evt.context.canvas.height);
          }
          evt.context.globalCompositeOperation = 'source-over';
      });

      var intensityInput = document.getElementById('intensity');
      var background = 255 - intensityInput.value;

      intensityInput.onchange = function() {
          background = 255 - intensityInput.value;
          map.render();
      };

      var grayInput = document.getElementById('gray');

      grayInput.onchange = function() {
          map.render();
      };

      var map = new ol.Map({
        layers: [mapLayer],
        target: 'map',
        view: new ol.View({
          center: [1331819, 7906244],
          zoom: 12
        })
      });
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
.map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 80%;
}
 <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" type="text/css">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>
<b>Gray:</b><input id="gray" type="range" min="0" max="100" step="1" value="50">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b>Intensity:</b><input id="intensity" type="range" min="0" max="255" step="1" value="128">


推荐阅读