mapboxgl載入tiff

来源:https://www.cnblogs.com/gisarmory/archive/2022/09/29/16740563.html
-Advertisement-
Play Games

一、項目優化 1.去掉列印console 需求:在開發環境中,保留列印console;在生產上線環境,自動去掉列印console 使用步驟: 第一步:在項目根目錄下,創建如下圖兩個配置文件 在.env.development中(開發環境變數) NODE_ENV=development 在.env.p ...


緣起

近期在項目中遇到這麼一個需求,需要在地圖上展示一組格網數據,格網大小為2m*2m,地圖api用的mapboxgl。起初拿到這個需要感覺很easy,在地圖上添加一個fill圖層就好啦。把格網面數據添加到地圖上之後,在大比例尺下顯示正常,但是當地圖層級小於15級時,渲染出的結果會消失。

簡單理一下原因,應該是在地圖縮小後,每個網格所占的像素太小,所以就消失了。

mapboxgl在處理symbol圖層的時候,會遇到點位自動避讓問題,導致部分點位不顯示。解決方法是把layout中的icon-allow-overlap設置為true,這樣就相當於關閉了自動避讓功能,所有點圖標保持可見狀態。但是針對fill圖層卻沒有這麼一個屬性。

但是這種情況又需要查看數據,要如何實現呢?

首先分析下數據,我的原始數據是通過模型導出的tiff格式的柵格數據,然後在後臺根據tiff格式數據中每個像素所在行列號以及其灰度值生成帶屬性的格網數據,其中像素的灰度值就是在渲染時需要分類展示的值。既然原始tiff數據的灰度值就是所用的屬性值,那是不是直接添加到地圖就好了。接下來的解決方案就是看是否能直接用mapboxgl直接載入tiff數據,並渲染出自己想要的效果。

mapboxgl載入tiff

查看mapboxgl文檔,可以看到mapboxgl支持image圖層,只需傳入url和coordinates

// 添加至地圖
map.addSource('some id', {
  type: 'image',
  url: 'https://www.mapbox.com/images/foo.png',
  coordinates: [
    [-76.54, 39.18],
    [-76.52, 39.18],
    [-76.52, 39.17],
    [-76.54, 39.17]
]});

可是,當我把地址換成tiff數據時卻報錯了。下麵為報錯內容:

Could not load image because of The source image could not be decoded.. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported

可以簡單理解為不支持tiff格式。

tiff文件解析

既然mapboxglimage圖層不支持tiff格式,那是不是可以把tiff數據導出成png呢,於是使用arcmap打開了tiff數據,導出數據格式也支持png,但是在保存時又報錯了。

經過分析,發現是tiff數據波段數量的原因,我的這份數據波段數為1,從網上下載了一份測試數據,波段數為3,可以成功導出。

在查找相關解決方案的時候,看到這麼個工具,geotiff.js,可以通過js解析tiff數據並渲染,leaflet有個擴展就是用的這個工具,https://github.com/stuartmatthews/leaflet-geotiff。查看geotiff.js相關文檔,發現其實用起來還是挺方便的,通過簡單的代碼實現的我的需求。

先使用geotiff.js解析tiff數據,再配合使用canvas繪製圖片導出base64格式數據,然後就可以使用添加到mapboxgl圖層了。

核心代碼如下:

async function getData() {
  GeoTIFF.fromUrl(url).then(tiff => {
    console.log(tiff)
    getImage(tiff)
  });
}
async function getImage(tiff) {
  const image = await tiff.getImage();
  let bbox = await image.getBoundingBox();
  let data = await image.readRasters({
    samples: rgbBands // 波段數量,一個波段:[0],三個波段:[2,1,0]
  });
  let base64Image = getBase64Image(data)
  addToMapboxgl(base64Image)
}
function getBase64Image(data) {
  let thumbnailPixelHeight = data.height
  let thumbnailPixelWidth = data.width
  let canvas = document.createElement('canvas')
  canvas.width = thumbnailPixelWidth
  canvas.height = thumbnailPixelHeight
  let ctx = canvas.getContext("2d")
  let totalPixelCount = 0
  for (let y = 0; y < thumbnailPixelHeight; y++) {
    for (let x = 0; x < thumbnailPixelWidth; x++) {
      let colour = 'rgb(0, 0, 0, 0)' // let the default be no data (transparent)
      // 根據灰度值所在範圍渲染顏色
      if (data[0][totalPixelCount] > 0) {
        if (data[0][totalPixelCount] > 50 && data[0][totalPixelCount] <= 55) {
          colour = `rgb(15, 255, 0, 1)`
        } else if (data[0][totalPixelCount] > 55 && data[0][totalPixelCount] <= 60) {
          colour = `rgb(155, 255, 0, 1)`
        } else if (data[0][totalPixelCount] > 60 && data[0][totalPixelCount] <= 65) {
          colour = `rgb(255, 255, 0, 1)`
        } else {
          colour = `rgb(255, 255, 0, 1)`
        }
      }
      ctx.fillStyle = colour
      ctx.fillRect(x, y, 1, 1)
      totalPixelCount++
    }
  }
  let canvasImage = canvas.toDataURL("image/png")
  return canvasImage
}
// 將圖片添加到地圖
function addToMapboxgl(image) {
  map.addSource('tiff-source', {
    "type": "image",
    "url": image,
    "coordinates": [
      [114.425597191307, 38.1091563484708],
      [114.538187627939, 38.1091563484708],
      [114.538187627939, 37.9627378349512],
      [114.425597191307, 37.9627378349512]
    ]
  });
  map.addLayer({
    id: 'tiff-layer',
    'type': 'raster',
    'source': 'tiff-source',
    'paint': {
      'raster-fade-duration': 0
    }
  });
}

本以為到這裡問題已經解決,但是在查看地圖時,發現圖片圖層數據疊加到底圖有不小的偏移。

經過一番對比分析,發現原來是tiff數據的坐標系與地圖坐標系不一致的導致的。我拿到的tiff數據坐標係為西安80的投影坐標系,在展示時配置的為wgs84地理坐標系,所以會有偏差。既然是坐標系問題,那就通過工具對tiff文件做下投影轉換。這裡用的是arcmap,打開ArcToolbox–>Data Management Tools–>Projections and Transformations–>Raster–>Project Raster

轉換之後會發現,數據的行列值也會發生變化,也就是tiff圖片的大小和形狀都有所變化。

轉換前:

轉換後:

使用轉換後的數據再次解析,然後疊加到地圖,位置完全匹配。

最終展示方案

通過嘗試發現,單獨的圖片展示時,由於圖片解析度固定,當地圖等級放大到一定程度圖片會被放大很多導致圖片模糊不清,展示效果不理想;單獨的格網面展示時,當地圖等級縮小到一定程度,面圖層則會消失,也就是文章開頭提到的問題。

綜上,根據自己的格網數據大小,判斷在哪個等級格網面數據會消失,小於這個等級使用圖片展示,大於這個等級用格網面展示,就可以完美的展示出想要的效果。

處理前效果:

處理前效果

處理後效果:

處理後效果

以上為有tiff柵格數據情況的解決方案,針對於只有格網面數據,而沒有tiff柵格數據的情況要怎麼解決呢?

如果在這組格網數據中,每個網格的屬性中有他所在原始tiff數據的像素位置,以及原始tiff數據像素大小,就可以寫一個類似上文中的getBase64Image方法,遍歷每個網格,在網格對應的像素位置上繪製顏色,然後再通過canvas導出圖片添加到地圖。

總結

  1. mapboxglimage圖層無法直接添加tiff柵格數據
  2. mapboxgl添加fill圖層時,地圖層級縮小到一定程度,面數據所占像素值過小無法顯示
  3. tiff數據可以使用geotiff.js+canvas解析,得到base64的圖片,添加到mapboxglimage圖層
  4. 在解析tiff數據時,需註意它的坐標系、波段個數等信息
  5. 在做展示時可以image圖層和fill圖層結合展示,效果較好

參考資料:

  1. https://geotiffjs.github.io/geotiff.js/
  2. https://github.com/stuartmatthews/leaflet-geotiff
  3. https://www.cnblogs.com/arxive/p/6746570.html

原文地址:http://gisarmory.xyz/blog/index.html?blog=mapboxgl-geotiff

歡迎關註《GIS兵器庫

本文章採用 知識共用署名-非商業性使用-相同方式共用 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發佈,但務必保留文章署名《GIS兵器庫》(包含鏈接:  http://gisarmory.xyz/blog/),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JavaScript排序 — sort()方法 ——解決null、undefined、0之間的排序(混亂)問題 一、普通的數組排序 ​ JavaScript中用方法sort()為數組排序。sort()方法有一個可選參數,是用來確定元素順序的函數。如果這個參數被省略,那麼數組中的元素將按照ASCII字 ...
  • ##vue路由守衛用於登錄驗證許可權攔截 ###vue路由守衛 - 全局(router.beforeEach((to, from, next) =>來判斷登錄和路由跳轉狀態) ###主要方法: to:進入到哪個路由去 from:從哪個路由離開 next:路由的控制參數,常用的有next(true)和n ...
  • LRU 是 Least Recently Used 的縮寫,即最近最少使用。作為一種經典的緩存策略,它的基本思想是長期不被使用的數據,在未來被用到的幾率也不大,所以當新的數據進來時我們可以優先把這些數據替換掉。 一、基本要求 固定大小:限制記憶體使用。 快速訪問:緩存插入和查找操作應該很快,最好是 O ...
  • 一、前言 前段時間碰到了一個 Keybinding 相關的問題,於是探究了一番,首先大家可能會有兩個問題:Monaco Editor 是啥?Keybinding 又是啥? Monaco Editor: 微軟開源的一個代碼編輯器,為 VS Code 的編輯器提供支持,Monaco Editor 核心代 ...
  • 語法&關鍵字與保留字 本章篇幅較長故分成幾個小節來講 語法 區分大小寫 這個沒啥好講的,a和A是兩個變數。 標識符 標識符,就是變數、函數、屬性或函數參數的名稱。 標識符的組成規範,如下: 第一個字元必須是一個字母、下劃線( _ )或者美元符號( $ ); 剩下的其他字元可以使字母、下劃線、美元符號 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 第一問:安全類型檢測——typeof和instanceof 區別以及缺陷,以及解決方案 這兩個方法都可以用來判斷變數類型 區別:前者是判斷這個變數是什麼類型,後者是判斷這個變數是不是某種類型,返回的是布爾值 (1)typeof 缺陷: 1 ...
  • 隨著NFC讀寫器在BS架構下的需求越來越多,使用JS語言在web瀏覽器下操作NFC讀寫器就變得尤其重要.但是web瀏覽器不允許其顯示內容直接操作硬體,所以我們必須使用IC卡讀卡器web插件來實現這個功能.作為web前端工程師,我們首先要瞭解在web中實現操作NFC讀寫器的步驟:1、下載友我科技IC卡 ...
  • NullPointerException在開發過程中經常遇到,稍有不慎小BUG就出現了,如果避免這個問題呢,Optional就是專門解決這個問題的類,那麼Optional如何使用呢?讓我們一起探索一下吧! ...
一周排行
    -Advertisement-
    Play Games
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...