四十八、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 sizeconst 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"><selectid="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><inputtype="range"v-model.number="palette.brightness"id="brightness"min="-100"max="100"value="0"@change="paletteChange"/><br /><label for="redInput">红:</label><inputtype="range"v-model="palette.red"id="redInput"min="0"max="2"step="0.01"@change="paletteChange"/><br /><label for="redInput">绿:</label><inputtype="range"v-model="palette.green"id="greenInput"min="0"max="2"step="0.01"@change="paletteChange"/><br /><label for="redInput">蓝:</label><inputtype="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 sizeconst 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>

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android串口助手apk下载 源码 演示 支持android 4-14及以上

android串口助手apk下载 1、自动获取串口列表 2、打开串口就开始接收 3、收发 字符或16进制 4、默认发送at\r\n 5、android串口助手apk 支持android 4-14 &#xff08;Google seral port 太老&#xff09; 源码找我 需要 用adb root 再setenforce 0进入SELinux 模式 才有权限…

关于docker无法正常下载镜像的问题

文章目录 之前还可以正常下载镜像&#xff0c;但是一段时间之后就无法下载了&#xff0c;猜测可能是政治原因&#xff0c;无法连接到国外服务器&#xff0c;所以我设置了阿里云的镜像加速器。 配置方法如下&#xff1a; 前往阿里云&#xff08;https://help.aliyun.com/zh/acr/…

理解HTTP请求格式

HTTP概念 HTTP全称HyperTextTransfer Protocol(超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议&#xff1b;HTTP是一个客户端&#xff08;用户&#xff09;和服务端&#xff08;网站&#xff09;之间请求和响应的标准。 HTTP 协议是以 ASCII 码传输&…

Ethena 更新代币经济学,逼着空投用户作长期 Hodler?

撰文&#xff1a;Yangz&#xff0c;Techub News 本文来源香港Web3媒体Techub News 6 月 18 日&#xff0c;Ethena 更新代币经济学&#xff0c;计划在 Ethena 生态和即将推出的 Ethena Chain 中引入通用再质押机制&#xff0c;并对任何通过空投获得 ENA 的用户实施「锁定」要求…

【黑马TS】学习资料Day4

五、在 React 中使用 TypeScript 现在&#xff0c;我们已经掌握了 TS 中基础类型、高级类型的使用了。但是&#xff0c;如果要在前端项目开发中使用 TS&#xff0c;还需要掌握 React、Vue、Angular 等这些库或框架中提供的 API 的类型&#xff0c;以及在 TS 中是如何使用的。 …

基于Redis提高查询性能(保持数据一致性)

Redis实战篇 | Kyles Blog (cyborg2077.github.io) 目录 背景 商户查询缓存(根据ID查询&#xff09; 根据店铺类型查询&#xff08;List型&#xff09; 缓存更新策略&#xff08;保证数据一致性&#xff09; 案例&#xff08;利用缓存更新策略&#xff09; 背景 起初客户端…

Hadoop3:MapReduce中的Shuffle机制

一、流程图 Shuffle是Map方法之后&#xff0c;Reduce方法之前的数据处理过程称。 二、图解说明 1、数据流向 map方法中context.write(outK, outV);开始&#xff0c;写入环形缓冲区&#xff0c;再进行分区排序&#xff0c;写到磁盘 reduce方法拉取磁盘上的数据&#xff0c;…

JavaSE 面向对象程序设计高级 方法引用 2024详解

在编程中&#xff0c;方法引用&#xff08;Method Reference&#xff09;是一种技术&#xff0c;它让你能够直接引用一个现有的函数或方法&#xff0c;而无需通过对象实例来调用。这种方法在函数式编程和高阶函数中非常有用&#xff0c;因为它提供了简洁的方式来传递函数行为&a…

【归档】maven的使用

学习自波波酱老师SSM企业级框架最全教学视频 maven篇 maven的设置 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…

【ARMv8/ARMv9 硬件加速系列 3 -- SVE 硬件加速向量运算 1】

文章目录 SVE 使用介绍SVE 特点SVE2 特点 SVE 寄存器扩展的向量寄存器可扩展的谓词寄存器.d 与 .b 后缀的区别举例介绍使用 .d 后缀进行64位元素操作使用 .b 后缀进行8位元素操作 ptrue 指令小结 FFR 寄存器 SVE 使用介绍 前面文章:【ARMv8/ARMv9 硬件加速系列 1 – SVE | NEO…

AttributeError: module ‘numpy‘ has no attribute ‘int‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

C++ Windows Hook使用

GitHub - microsoft/Detours: Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form. /*挂载钩子 setdll /d:C:\Users\g\source\repos\LotTest\Release\lotDll.dll C:\Users\g\source\repos\LotTest…

React 通信:深层传递(Props、Context、Children Jsx)

在之前的文章 探讨&#xff1a;围绕 props 阐述 React 通信 中总结了关于“父子”组件传值&#xff0c;但是当需要在组件树中深层传递参数以及需要在组件间复用相同的参数时&#xff0c;传递 props 就会变得很麻烦。 实际案例&#xff1a; 下述展示有两种状态&#xff1a;① 详…

【无线传感网】LEACH路由算法

1、LEACH路由算法简介 LEACH协议,全称是“低功耗自适应集簇分层型协议” (Low Energy Adaptive Clustering Hierarchy),是一种无线传感器网络路由协议。基于LEACH协议的算法,称为LEACH算法。 2、LEACH路由算法的基本思想 LEACH路由协议与以往的路由协议的不同之处在于其改变…

<Rust><iced>基于rust使用iced构建GUI实例:如何将svg格式转为ico格式图片?

前言 本专栏是Rust实例应用。 环境配置 平台:windows 软件:vscode 语言:rust 库:iced、iced_aw 概述 本文是专栏第4篇实例,依旧是一个图像格式转换程序,基于rust的svg库resvg、图像处理库image以及文件处理库rfd。 流程是先用resvg获取svg图片的数据并将其转为png数据…

嵌入式实验---实验一 通用GPIO实验

一、实验目的 1、掌握STM32F103 GPIO程序设计流程&#xff1b; 2、熟悉STM32固件库的基本使用。 二、实验原理 1、通过按键实现&#xff1a;按键按下&#xff0c;LED点亮&#xff1b;按键释放&#xff0c;LED熄灭。 三、实验设备和器材 电脑、Keil uVision5软件、Proteus…

清凉夏日运动新选择——气膜体育馆—轻空间

随着气温的不断攀升&#xff0c;夏天成为许多运动爱好者的挑战季节。炎热的天气不仅容易让人感到疲倦&#xff0c;更可能带来中暑等健康风险。然而&#xff0c;气膜体育馆的出现&#xff0c;为爱好运动的你提供了一个理想的避暑之地。气膜体育馆以其独特的结构和诸多优势&#…

【ARM】如何通过Keil MDK查看芯片的硬件信息

【更多软件使用问题请点击亿道电子官方网站】 1、文档目标&#xff1a; 解决在开发过程中对于开发项目所使用的的芯片的参数查看的问题 2、问题场景&#xff1a; 在项目开发过程中&#xff0c;经常需要对于芯片的时钟、寄存器或者一些硬件参数需要进行确认。大多数情况下是需…

【科研基础】通感一体化讲座

通信和感知在硬件结构上相似&#xff0c;高效地利用资源&#xff0c;实现相互的增益&#xff1b; 感知是基于不同的任务&#xff0c;比如

从零开始的<vue2项目脚手架>搭建:vite+vue2+eslint

前言 为了写 demo 或者研究某些问题&#xff0c;我经常需要新建空项目。每次搭建项目都要从头配置&#xff0c;很麻烦。所以我决定自己搭建一个项目初始化的脚手架&#xff08;取名为 lily-cli&#xff09;。 脚手架&#xff08;scaffolding&#xff09;&#xff1a;创建项目时…