四十八、openlayers地图调色总结——锐化、模糊、浮雕滤镜,调整地图色相、饱和度、亮度

 

 

这篇是对滤镜的总结,方便工作中直接使用。

想要调整图层的颜色,有两种方法。

方法一:

 加载图层时使用tileLoadFunction函数拿到context添加canvas滤镜效果。

 this.imagery = new TileLayer({
        source: new XYZ({
          url: "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
          crossOrigin: "anonymous",
            tileLoadFunction: function (imageTile, src) {
              let img = new Image();
              // 设置图片不从缓存取,从缓存取可能会出现跨域,导致加载失败
              img.setAttribute("crossOrigin", "anonymous");
              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;
            },
        }),
      });
方法二:

利用postrender事件手动获取像素数据修改每一个像素点的值。

   this.imagery.on("postrender", (event) => {
      this.convolve(event.context, this.selectedKernel);
    });
convolve(context, kernel) {
      const canvas = context.canvas;
      const width = canvas.width;
      const height = canvas.height;
      // 假设 kernel 是一个归一化的卷积核矩阵,其大小为 size x size
      const size = Math.sqrt(kernel.length);
      const half = Math.floor(size / 2);
      // 获取输入图像数据
      const inputData = context.getImageData(0, 0, width, height).data;
      // 创建一个新的 ImageData 对象用于输出图像数据
      const output = context.createImageData(width, height);
      const outputData = output.data;
      //   遍历每个像素
      for (let pixelY = 0; pixelY < height; ++pixelY) {
        const pixelsAbove = pixelY * width;
        for (let pixelX = 0; pixelX < width; ++pixelX) {
          let r = 0,
            g = 0,
            b = 0,
            a = 0;
          // 遍历卷积核
          for (let kernelY = 0; kernelY < size; ++kernelY) {
            for (let kernelX = 0; kernelX < size; ++kernelX) {
              let weight = kernel[kernelY * size + kernelX];
              const neighborY = Math.min(
                height - 1,
                Math.max(0, pixelY + kernelY - half)
              );
              const neighborX = Math.min(
                width - 1,
                Math.max(0, pixelX + kernelX - half)
              );
              const inputIndex = (neighborY * width + neighborX) * 4;

              // 累加加权后的像素值
              r += inputData[inputIndex] * weight;
              g += inputData[inputIndex + 1] * weight;
              b += inputData[inputIndex + 2] * weight;
              a += inputData[inputIndex + 3] * weight;
            }
          }
          const outputIndex = (pixelsAbove + pixelX) * 4;
          outputData[outputIndex] = r;
          outputData[outputIndex + 1] = g;
          outputData[outputIndex + 2] = b;
          outputData[outputIndex + 3] = kernel.normalized ? a : 255; // 如果卷积核是归一化的,则使用计算后的 alpha,否则设为 255
          //添加红绿蓝通道的值
          outputData[outputIndex] *= this.palette.red;
          outputData[outputIndex + 1] *= this.palette.green;
          outputData[outputIndex + 2] *= this.palette.blue;
          //添加亮度
          outputData[outputIndex] += this.palette.brightness;
          outputData[outputIndex + 1] += this.palette.brightness;
          outputData[outputIndex + 2] += this.palette.brightness;
        }
      }
      context.putImageData(output, 0, 0);
    },

 如果要添加模糊、锐化、浮雕等效果需要进行卷积核相关的操作,如果只是修改颜色则不需要。

两种方法总结:

第一种比较简单,代码较少。

第二种代码较多,但是修改的自由度比较高,可以添加更多的效果。 

第二种方法的原理可以看这篇:

四十七、openlayers官网示例Image Filters——给地图添加锐化、浮雕、边缘等滤镜效果-CSDN博客

 完整代码:

<template>
  <div class="box">
    <h1>滤镜效果</h1>
    <div id="map" class="map"></div>
    <div class="tools">
      <select
        id="kernel"
        name="kernel"
        style="height: 20px; margin-right: 20px"
        @change="paletteChange"
        v-model="kernelValue"
      >
        <option v-for="(value, key, index) in kernels" :key="index">
          {{ key }}
        </option>
      </select>
      <div>
        <label for="brightness">亮度:</label>
        <input
          type="range"
          v-model.number="palette.brightness"
          id="brightness"
          min="-100"
          max="100"
          value="0"
          @change="paletteChange"
        />
        <br />
        <label for="redInput">红:</label>
        <input
          type="range"
          v-model="palette.red"
          id="redInput"
          min="0"
          max="2"
          step="0.01"
          @change="paletteChange"
        />
        <br />
        <label for="redInput">绿:</label>
        <input
          type="range"
          v-model="palette.green"
          id="greenInput"
          min="0"
          max="2"
          step="0.01"
          @change="paletteChange"
        />
        <br />
        <label for="redInput">蓝:</label>
        <input
          type="range"
          v-model="palette.blue"
          id="blueInput"
          min="0"
          max="2"
          step="0.01"
          @change="paletteChange"
        />
      </div>
    </div>
  </div>
</template>

<script>
import Map from "ol/Map.js";
import View from "ol/View.js";
import XYZ from "ol/source/XYZ.js";
import { fromLonLat } from "ol/proj.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
import { OGCMapTile, Vector as VectorSource } from "ol/source.js";
export default {
  name: "",
  components: {},
  data() {
    return {
      map: null,
      extentData: "",
      palette: {
        brightness: 0,
        red: 1,
        green: 1,
        blue: 1,
      },
      imagery: null,
      //卷积核
      kernels: {
        none: [0, 0, 0, 0, 1, 0, 0, 0, 0], //无
        sharpen: [0, -1, 0, -1, 5, -1, 0, -1, 0], //锐化滤波器
        sharpenless: [0, -1, 0, -1, 10, -1, 0, -1, 0], //增强图像的边缘和细节,但比 sharpen 更强烈。
        blur: [1, 1, 1, 1, 1, 1, 1, 1, 1], //平滑滤波器,通过对邻域像素值求平均来模糊图像
        shadow: [1, 2, 1, 0, 1, 0, -1, -2, -1], //阴影滤波器
        emboss: [-2, 1, 0, -1, 1, 1, 0, 1, 2], //浮雕滤波器
        edge: [0, 1, 0, 1, -4, 1, 0, 1, 0], //边缘检测滤波器
      },
      kernelValue: "none",
      selectedKernel: "",
    };
  },
  computed: {},
  created() {},
  mounted() {
    this.initMap();

    this.selectedKernel = this.normalize(this.kernels[this.kernelValue]);

    this.imagery.on("postrender", (event) => {
      this.convolve(event.context, this.selectedKernel);
    });
  },
  methods: {
    convolve(context, kernel) {
      const canvas = context.canvas;
      const width = canvas.width;
      const height = canvas.height;
      // 假设 kernel 是一个归一化的卷积核矩阵,其大小为 size x size
      const size = Math.sqrt(kernel.length);
      const half = Math.floor(size / 2);
      // 获取输入图像数据
      const inputData = context.getImageData(0, 0, width, height).data;
      // 创建一个新的 ImageData 对象用于输出图像数据
      const output = context.createImageData(width, height);
      const outputData = output.data;
      //   遍历每个像素
      for (let pixelY = 0; pixelY < height; ++pixelY) {
        const pixelsAbove = pixelY * width;
        for (let pixelX = 0; pixelX < width; ++pixelX) {
          let r = 0,
            g = 0,
            b = 0,
            a = 0;
          // 遍历卷积核
          for (let kernelY = 0; kernelY < size; ++kernelY) {
            for (let kernelX = 0; kernelX < size; ++kernelX) {
              let weight = kernel[kernelY * size + kernelX];
              const neighborY = Math.min(
                height - 1,
                Math.max(0, pixelY + kernelY - half)
              );
              const neighborX = Math.min(
                width - 1,
                Math.max(0, pixelX + kernelX - half)
              );
              const inputIndex = (neighborY * width + neighborX) * 4;

              // 累加加权后的像素值
              r += inputData[inputIndex] * weight;
              g += inputData[inputIndex + 1] * weight;
              b += inputData[inputIndex + 2] * weight;
              a += inputData[inputIndex + 3] * weight;
            }
          }
          const outputIndex = (pixelsAbove + pixelX) * 4;
          outputData[outputIndex] = r;
          outputData[outputIndex + 1] = g;
          outputData[outputIndex + 2] = b;
          outputData[outputIndex + 3] = kernel.normalized ? a : 255; // 如果卷积核是归一化的,则使用计算后的 alpha,否则设为 255
          //添加红绿蓝通道的值
          outputData[outputIndex] *= this.palette.red;
          outputData[outputIndex + 1] *= this.palette.green;
          outputData[outputIndex + 2] *= this.palette.blue;
          //添加亮度
          outputData[outputIndex] += this.palette.brightness;
          outputData[outputIndex + 1] += this.palette.brightness;
          outputData[outputIndex + 2] += this.palette.brightness;
        }
      }
      context.putImageData(output, 0, 0);
    },
    normalize(kernel) {
      // 获取卷积核的长度
      const len = kernel.length;
      // 创建一个与卷积核相同长度的新数组
      const normal = new Array(len);
      let i,
        sum = 0;
      // 计算卷积核中所有元素的总和
      for (i = 0; i < len; ++i) {
        sum += kernel[i];
      }
      // 如果总和小于等于0,设置sum为1并标记为未归一化
      if (sum <= 0) {
        normal.normalized = false;
        sum = 1;
      } else {
        // 如果总和大于0,标记为已归一化
        normal.normalized = true;
      }
      // 将卷积核中的每个元素除以总和,得到归一化后的值
      for (i = 0; i < len; ++i) {
        normal[i] = kernel[i] / sum;
      }
      // 返回归一化后的卷积核
      return normal;
    },
    initMap() {
      this.imagery = new TileLayer({
        source: new XYZ({
          url: "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
          crossOrigin: "anonymous",
            // tileLoadFunction: function (imageTile, src) {
            //   let img = new Image();
            //   // 设置图片不从缓存取,从缓存取可能会出现跨域,导致加载失败
            //   img.setAttribute("crossOrigin", "anonymous");
            //   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;
            // },
        }),
      });
      this.map = new Map({
        layers: [this.imagery],
        target: "map",
        view: new View({
          center: fromLonLat([-120, 50]),
          zoom: 6,
        }),
      });
    },
    paletteChange() {
      console.log("this.palette", this.palette);
      this.selectedKernel = this.normalize(this.kernels[this.kernelValue]);
      this.map.render();
    },
  },
};
</script>

<style lang="scss" scoped>
#map {
  width: 100%;
  height: 500px;
}
.box {
  height: 100%;
}
.tools {
  display: flex;
}
</style>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/724615.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

渲染农场深度解析:原理理解、配置要点与高效使用策略

许多设计领域的新手可能对“渲染农场”这一概念感到陌生。渲染农场是一种强大的计算资源集合&#xff0c;它通过高性能的CPU和GPU以及专业的渲染引擎&#xff0c;为设计项目提供必要的渲染支持。这种平台由多台计算机或渲染节点组成&#xff0c;形成一个分布式网络&#xff0c;…

第四篇:精通Docker构建:Dockerfile的艺术与策略

精通Docker构建&#xff1a;Dockerfile的艺术与策略 1. 开篇&#xff1a;探索Docker的革命 在探讨我们的主题之前&#xff0c;让我们先回顾一下Docker的概念。Docker是一个开源平台&#xff0c;用于自动化应用程序的部署、扩展和管理&#xff0c;这一切都是在轻量级的容器中进…

6月17日(周一)美国股市行情总结:标普纳指齐新高,AI和芯片股尤为出色

标普500指数在六天里第五天上涨&#xff0c;纳指和纳指100均连续六日新高&#xff0c;道指止步四日连跌脱离近两周低位&#xff0c;罗素小盘股指止步两日连跌并脱离六周最低。微软收盘市值仍为美股第一、苹果为第二、英伟达第三&#xff0c;但早盘触及盘中新高的英伟达市值曾超…

Linux虚拟机安装nginx并进行浏览器访问 - 附带常见问题和常用指令(实施必备)

1、Linux安装Nginx 1.1、下载Nginx安装包 Linux Nginx-1.25.5 官方其他版本 1.2、解压安装包 tar -zxvf nginx-1.25.5.tar.gz 1.3、安装依赖包 由于我使用的是1.25.5版本&#xff0c;所以需要加入依赖包 # yum install pcre pcre-devel # yum install zlib-devel 1.4、配置…

数据集制作——语义分割前png、jpg格式标签图转yolo格式.txt文件(附代码)

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

【论文阅读】MOA,《Mixture-of-Agents Enhances Large Language Model Capabilities》

前面大概了解了Together AI的新研究MoA&#xff0c;比较好奇具体的实现方法&#xff0c;所以再来看一下对应的文章论文。 论文&#xff1a;《Mixture-of-Agents Enhances Large Language Model Capabilities》 论文链接&#xff1a;https://arxiv.org/html/2406.04692v1 这篇文…

Qt入门小项目 | 实现一个图片查看器

文章目录 一、实现一个图片查看软件 一、实现一个图片查看软件 需要实现的功能&#xff1a; 打开目录选择图片显示图片的名字显示图片 在以上功能的基础上进行优化&#xff0c;需要解决如下问题&#xff1a; 如何记住上次打开的路径&#xff1f; 将路径保存到配置文件中&#x…

天地图(二)引入地图

1、在public下的index.html中引入天地图 <script src"http://api.tianditu.gov.cn/api?v4.0&tk你的密钥"></script> 2、在vue文件中写入 <template><div:id"mapDiv currentIndex"class"map"style"position: a…

VMware 虚拟机共享宿主机文件夹

一、背景 在虚拟机中&#xff0c;需要写文件到宿主机的文件系统中 宿主机的文件共享给虚拟机使用 这些场景就涉及到VM的虚拟机怎么访问宿主机的磁盘文件夹 二、软件背景 宿主机&#xff1a;window机器&#xff0c;本文是win7 虚拟软件&#xff1a;VMware12.5.6&#xff0…

STM32学习记录(八)————定时器输出PWM及舵机的控制

文章目录 前言一、PWM1.工作原理2.内部运作机制3. PWM工作模式4.PWM结构体及库函数 二、PWM控制舵机 前言 一个学习STM32的小白~ 有错误评论区或私信指出提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、PWM 1.工作原理 以向上计数为例&#xff0…

钡铼BL102应用智能电网配电柜PLC转MQTT无线接云服务

在当今智能电网的发展浪潮中&#xff0c;配电系统的智能化升级是提升电网效率与稳定性的重要环节。随着物联网技术的飞速发展&#xff0c;实现配电柜的远程监控与管理成为了可能&#xff0c;而这一转变的关键在于如何有效地将传统配电柜中的PLC数据接入到云端进行分析与处理。 …

ui自动化中,隐式等待和显示等待什么时候使用

隐式等待 在页面刷新加载时&#xff0c;页面元素还没有出来&#xff0c;这个时候如果去找元素就会找不到报错 或者点了一个菜单&#xff0c;页面加载时 用笨办法&#xff0c;就是用sleep等待固定的时间&#xff0c;这种浪费的时间比较多&#xff0c;就可以用隐式等待&#xf…

CleanShot X for Mac v4.7 屏幕截图录像工具(保姆级教程,小白轻松上手,简单易学)

Mac分享吧 文章目录 一、准备工作二、部分特有功能效果1、截图软件的普遍常用功能&#xff08;画框、箭头、加文字等&#xff09;都具备&#xff0c;不再详细介绍2、ABCD、1234等信息标注&#xff08;每按一下鼠标&#xff0c;即各是A、B、C、D...等&#xff09;3、截图更换背…

大语言模型架构---Transformer 模型

文章目录 输入编码多头自注意力机制前馈网络层编码器解码器当前主流的大语言模型都基于 Transformer 模型进行设计的。Transformer 是由多层的多头自注意力(Multi-head Self-attention)模块堆叠而成的神经网络模型。原始的 Transformer 模型由编码器和解码器两个部分构成,而…

KVB外汇:周四英国央行利率决议,英镑跌破1.26支撑的可能性有多大?

摘要&#xff1a; 本文分析了即将到来的英国央行利率决议对英镑汇率可能带来的影响。尽管市场普遍预计央行将维持利率不变&#xff0c;但随着通胀下降&#xff0c;意外降息的可能性仍然存在。文章探讨了汇市的反应预期、技术支撑位的重要性以及可能的货币政策走向&#xff0c;…

线程间通信

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 我们已经知道进程之间不能直接共享信息&#xff0c;那么线程之间可以共享信息吗&#xff1f;我们通过一个例子来验证一下。定义一个全局变量g_num&am…

C++设计模式——Proxy代理模式

一&#xff0c;代理模式简介 代理模式是一种 结构型设计模式&#xff0c;该模式通过引入一个新的代理对象Proxy&#xff0c;来间接访问原始对象&#xff0c;从而使访问方式变得灵活和可控。 代理对象的设定减少了客户端与真实对象之间的直接交互。 通过引入代理对象来间接访问原…

【diffusers 极速入门(二)】如何得到扩散去噪的中间结果?Pipeline callbacks 管道回调函数

本文是对 Hugging Face Diffusers 文档中关于回调函数的翻译与总结&#xff0c;&#xff1a; 管道回调函数 在管道的去噪循环中&#xff0c;可以使用callback_on_step_end参数添加自定义回调函数。该回调函数在每一步结束时执行&#xff0c;并修改管道属性和变量&#xff0c;以…

2024青海三支一扶招1910人7月6日笔试

&#x1f4e2;2024年青海省三支一扶计划招募1910人公告已发布&#xff01; 小&#x1f004;️帮大家整理好了考试关键时间点&#xff1a; ★ 报名时间&#xff1a;6月20日至6月25日 ★ 报名网站&#xff1a;青海省人事考试信息网&#xff08;www.qhpta.com&#xff09; ★ 网上…