七、openlayers官网示例Band Contrast Stretch解析——加载地图并修改颜色

这个示例讲的是如何修改地图的颜色。

先初始化一个地图

this.map = new Map({
        target: "map",
        view: new View({
          projection: "EPSG:4326",
          center: [0, 0],
          zoom: 2,
          maxZoom: 12,
        }),
      });

初始化一个颜色信息的对象

 colorObj: {
        redMax: 3500,
        greenMax: 3500,
        blueMax: 3500,
        red: 1,
        green: 2,
        blue: 3,
      },

加载geotiff格式的地图,TileLayer表示瓦片图层,color定义了图层样式数组。其中["/", ["band", ["var", "red"]], ["var", "redMax"]]:是一个颜色通道的定义。它使用了一个除法运算符 "/",将图像的一个波段(band)值除以一个最大值来计算颜色通道的值。["band", ["var", "red"]] 表示取图像的红色波段的值,["var", "redMax"] 表示取 redMax 变量的值作为最大值。1表示透明度。通过计算图像的红、绿、蓝通道的值,以及设定的最大值,来确定图像的颜色。(平时拿ps软件p图的时候也是调节的红绿蓝通道,具体原理及操作我这个非专业人士也不是很了解)。

   addGeoTifLayer() {
      this.geoTifLayer = new TileLayer({
        style: {
          variables: this.colorObj,
          color: [
            "array",
            ["/", ["band", ["var", "red"]], ["var", "redMax"]],
            ["/", ["band", ["var", "green"]], ["var", "greenMax"]],
            ["/", ["band", ["var", "blue"]], ["var", "blueMax"]],
            1,
          ],
        },
        source: new GeoTIFF({
          normalize: false,
          sources: [
            {
              url: `https://s2downloads.eox.at/demo/EOxCloudless/2020/
rgbnir/s2cloudless2020-16bits_sinlge-file_z0-4.tif`,
            },
          ],
        }),
      });
      this.map.addLayer(this.geoTifLayer);
    },

然后html里写了选框和滑块动态调整值,生成一个颜色信息对象,调用updateStyleVariables就可以实现动态修改地图颜色了。现实需求中,如果修改地图颜色只是为了完成UI设计,可以使用滑块调节好了把colorObj的值直接复制过去。注意传递的对象里的值要是数字格式的。

我这里用vue的语法改写了事件,v-model.number让获取到的滑块的值是数字而非字符串。

 <label for="blue">蓝</label>
      <select id="blue" @change="update" v-model="colorObj.blue">
        <option :value="1">visible red</option>
        <option :value="2">visible green</option>
        <option :value="3" selected>visible blue</option>
        <option :value="4">near infrared</option>
      </select>
      <label
        >max
        <input
          type="range"
          @input="update"
          id="blueMax"
          :min="2000"
          :max="5000"
          v-model.number="colorObj.blueMax"
        />
      </label>

值得我们注意的是,不是所有地图都可以通过这种方式去修改颜色的,只有使用geotiff格式的地图才可以。原谅我目前我还没找到别的地图可以这样修改颜色的/😓/,学习的道路漫长且艰辛,待我慢慢踩坑。。

但是之前工作中用另外一种方式修改了地图颜色,这里给大家也分享下,这种思路主要是在图层加载时,在tileLoadFunction函数里面拿到每个切片的图像src,手动绘制canvas把图片加上去,并通过context.filter给图片添加滤镜。调节滤镜的参数即可修改颜色。我这里使用的底图是arcgis的,这里使用天地图、高德地图等其他地图也是可以的。

addunderLayer() {
      const layer = new Tile({
        source: new XYZ({
          url: `https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}`,
          tileLoadFunction: function (imageTile, src) {
            let img = new Image();
            img.crossOrigin = "";
            img.onload = function () {
              let canvas = document.createElement("canvas");
              let w = img.width;
              let h = img.height;
              canvas.width = w;
              canvas.height = h;
              let context = canvas.getContext("2d");
              context.filter =
                "grayscale(0%) invert(15%) sepia(0%) hue-rotate(75deg) saturate(200%) brightness(100%) contrast(100%)";
              // grayscale 灰度   invert反相   sepia将图像转化成深褐色  saturate饱和度   brightness暗度 contrast对比度
              context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
              imageTile.getImage().src = canvas.toDataURL("image/png");
            };
            img.src = src;
          },
        }),
        zIndex: 1,
      });
      this.map.addLayer(layer);
    },

完整代码:

<template>
  <div class="box">
    <h1>BandContrastStretch</h1>
    <div id="map"></div>
    <div class="controls">
      <label for="red">红</label>
      <select id="red" @change="update" v-model="colorObj.red">
        <option :value="1" selected>visible red</option>
        <option :value="2">visible green</option>
        <option :value="3">visible blue</option>
        <option :value="4">near infrared</option>
      </select>
      <label
        >max
        <input
          type="range"
          id="redMax"
          @input="update"
          v-model.number="colorObj.redMax"
          :min="2000"
          :max="5000"
        />
      </label>

      <label for="green">绿</label>
      <select id="green" @change="update" v-model="colorObj.green">
        <option :value="1">visible red</option>
        <option :value="2" selected>visible green</option>
        <option :value="3">visible blue</option>
        <option :value="4">near infrared</option>
      </select>
      <label
        >max
        <input
          type="range"
          id="greenMax"
          @input="update"
          :min="2000"
          v-model.number="colorObj.greenMax"
          :max="5000"
        />
      </label>

      <label for="blue">蓝</label>
      <select id="blue" @change="update" v-model="colorObj.blue">
        <option :value="1">visible red</option>
        <option :value="2">visible green</option>
        <option :value="3" selected>visible blue</option>
        <option :value="4">near infrared</option>
      </select>
      <label
        >max
        <input
          type="range"
          @input="update"
          id="blueMax"
          :min="2000"
          :max="5000"
          v-model.number="colorObj.blueMax"
        />
      </label>
    </div>
  </div>
</template>

<script>
import GeoTIFF from "ol/source/GeoTIFF.js";
import Map from "ol/Map.js";
import TileLayer from "ol/layer/WebGLTile.js";
import Tile from "ol/layer/Tile.js";
import View from "ol/View.js";
import { XYZ } from "ol/source";

export default {
  name: "",
  components: {},
  data() {
    return {
      map: null,
      geoTifLayer: null,
      colorObj: {
        redMax: 3500,
        greenMax: 3500,
        blueMax: 3500,
        red: 1,
        green: 2,
        blue: 3,
      },
    };
  },
  computed: {},
  created() {},
  methods: {
    initMap() {
      this.map = new Map({
        target: "map",
        view: new View({
          projection: "EPSG:4326",
          center: [0, 0],
          zoom: 2,
          maxZoom: 12,
        }),
      });
    },
    update() {
      this.geoTifLayer.updateStyleVariables(this.colorObj);
    },
    addGeoTifLayer() {
      this.geoTifLayer = new TileLayer({
        style: {
          variables: this.colorObj,
          color: [
            "array",
            ["/", ["band", ["var", "red"]], ["var", "redMax"]],
            ["/", ["band", ["var", "green"]], ["var", "greenMax"]],
            ["/", ["band", ["var", "blue"]], ["var", "blueMax"]],
            1,
          ],
        },
        source: new GeoTIFF({
          normalize: false,
          sources: [
            {
              url: "https://s2downloads.eox.at/demo/EOxCloudless/2020/rgbnir/s2cloudless2020-16bits_sinlge-file_z0-4.tif",
            },
          ],
        }),
      });
      this.map.addLayer(this.geoTifLayer);
    },
    addunderLayer() {
      const layer = new Tile({
        source: new XYZ({
          url: `https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}`,
          tileLoadFunction: function (imageTile, src) {
            console.log('src',src);
            let img = new Image();
            img.crossOrigin = "";
            img.onload = function () {
              let canvas = document.createElement("canvas");
              let w = img.width;
              let h = img.height;
              canvas.width = w;
              canvas.height = h;
              let context = canvas.getContext("2d");
              context.filter =
                "grayscale(0%) invert(15%) sepia(0%) hue-rotate(75deg) saturate(200%) brightness(100%) contrast(100%)";
              // grayscale 灰度   invert反相   sepia将图像转化成深褐色  saturate饱和度   brightness暗度 contrast对比度
              context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
              imageTile.getImage().src = canvas.toDataURL("image/png");
            };
            img.src = src;
          },
        }),
        zIndex: 1,
      });
      this.map.addLayer(layer);
    },
  },
  mounted() {
    this.initMap();
    this.addGeoTifLayer();
    // this.addunderLayer();
  },
};
</script>

<style lang="scss" scoped>
#map {
  width: 100%;
  height: 500px;
}
.box {
  height: 100%;
}
.controls {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: baseline;
  gap: 0 1em;
}
</style>

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值