Hilbert編碼 思路和scala 代碼

需求:

使用Hilbert 曲線對遙感影像瓦片數據進行編碼,獲取某個區域的編碼值即可

Hilbert 曲線編碼方式

思路

大致可以對四個方向的數據進行歸類

  1. 左下
  2. 左上
  3. 右上
  4. 右下

這個也對應著編碼的順序

思考在不同Hilbert深度(階)情況下的四個區域的取值范圍

  1. 左下

    [ 0 , 4 n ? 1 ) [0,4^{n-1}) [0,4n?1)

  2. 左上

    [ 4 n ? 1 , 2 × 4 n ? 1 ) [4^{n-1}, \ 2\ \times \ 4^{n-1}) [4n?1,?2?×?4n?1)

  3. 右上

    [ 2 × 4 n ? 1 , 3 × 4 n ? 1 ) [2\ \times\ 4^{n-1},3 \times4^{n-1}) [2?×?4n?1,3×4n?1)

  4. 右下

    [ 3 × 4 n ? 1 , 4 n ) [3 \ \times \ 4^{n-1}, 4^n) [3?×?4n?1,4n)

因此可以使用遞歸的方式來進行生成數據

主要問題

左上角和右上角不需要做旋轉操作

 // 左上角,待判定點不需要做任何調整,直接遞歸新子區域即可case (true, false)  =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), Point(bounds._1.lat,bounds._2.lon)), maxLevel - 1 ) +   Math.pow(4, maxLevel-2).toInt// 右上角case (false, false) =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), bounds._2), maxLevel - 1) + 2 * Math.pow(4, maxLevel - 2).toInt

左下角和左上角需要考慮旋轉問題

可以使用舉例子的方式,來找到旋轉后的關系

假設空間區域的左下角坐標為(10,20),右上角的坐標為(20,30),中心坐標為(15, 25)

同樣以二階圖為例

這里點位置變更主要針對的是待判定的位置屬于哪個區域!

Hilbert 編碼區域左下區域(左側為原始點位置,右側為旋轉后的點位置)

(18,22.5)=> (12.5,28)

(17.5,22) => (12,27.5)

Hilbert 編碼區域右下區域

(12,27.5)=>(12.5, 28)

(12.5, 22) => (18, 27.5)

左下旋轉后坐標生成方式

原始點位置-中心點位置 = (a,b)

結果 = 中心點位置 + (b,a)

例:(18,22.5) - (15,25) = (3,-2.5)

結果 = (15,25 ) + (-2.5, 3) = (12.5, 28)

右下旋轉后坐標生成方式

原始點位置-中心點位置 = (a,b)

結果 = 中心點位置 -(b,a)

例: (12, 27.5) - (15,25) = (-3,2.5)

結果 = (15,25) -(2.5,-3) = (12.5,28)

思路捋清之后,可以考慮代碼

// 左下角,case (true, true)   =>recursiveHilbertEncode(Point(lat_half + lon_reverse,lon_half + lat_reverse),   (bounds._1, Point(lat_half, lon_half)),maxLevel - 1)// 右下角case (false, true)  =>recursiveHilbertEncode(Point(lat_half - lon_reverse,lon_half - lat_reverse), ((Point(lat_half,bounds._1.lon),Point(bounds._2.lat,lon_half))), maxLevel - 1) + 3 * Math.pow(4, maxLevel-2).toInt

需要對待判定點重新生成,但區域的經緯坐標可以不變,我們不關系點坐標怎么變換,我們只是需要最終的編碼結果,保證遞歸正常運行即可

Hilbert 源碼生成

input:

  1. 正方形邊界兩個對角頂點的坐標
  2. 最大Hilbert 層級(階、深度)
  3. 待判定的區域兩點坐標(或者是一個點)

output:

該區域(區域也是計算區域的中心點位置)、點所在的Hilbert 編碼值

遞歸函數

recursiveHilbertEncode

  def recursiveHilbertEncode(point: Point, bounds:(Point,Point), maxLevel:Int): Int = {if (maxLevel == 1)return 0// 邊界中心點val lat_half = (bounds._1.lat + bounds._2.lat) / 2 //xval lon_half = (bounds._1.lon + bounds._2.lon) / 2 //y// 反轉差值val lat_reverse = point.lat - lat_halfval lon_reverse = point.lon - lon_half(point.lat < lat_half, point.lon < lon_half) match {// 右上角 , p1,p2 不需要動,需要動的是邊界和case (false, false) =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), bounds._2), maxLevel - 1) + 2 * Math.pow(4, maxLevel - 2).toInt// 右下角 向左旋轉case (false, true)  =>recursiveHilbertEncode(Point(lat_half - lon_reverse,lon_half - lat_reverse), ((Point(lat_half,bounds._1.lon),Point(bounds._2.lat,lon_half))), maxLevel - 1) + 3 * Math.pow(4, maxLevel-2).toInt//左上case (true, false)  =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), Point(bounds._1.lat,bounds._2.lon)), maxLevel - 1 ) +   Math.pow(4, maxLevel-2).toInt// 左下角 向右旋轉case (true, true)   =>recursiveHilbertEncode(Point(lat_half + lon_reverse,lon_half + lat_reverse),   (bounds._1, Point(lat_half, lon_half)),maxLevel - 1)}}

完整代碼

測試代碼沒整理,有兩個main函數,一個是零散的編碼區域,一個是從0-15區域的編碼結果

import HilbertCurve.getTileCodeobject HilbertCurve {case class Point(lat: Double, lon: Double)// 遞歸查看Hilbert編碼/*** 瓦片中心點坐標* 新bounds邊界(其實也是用來定義邊界的中心點的)* maxLevel* @return*/def recursiveHilbertEncode(point: Point, bounds:(Point,Point), maxLevel:Int): Int = {if (maxLevel == 1)return 0// 邊界中心點val lat_half = (bounds._1.lat + bounds._2.lat) / 2 //xval lon_half = (bounds._1.lon + bounds._2.lon) / 2 //y
//
//    println("邊界中心點  :(" + lat_half + ", " + lon_half + ")")
//
//    println("瓦片中心點:(" + point.lat + ", " + point.lon + ")")// point 為瓦片的中心點// 反轉差值val lat_reverse = point.lat - lat_halfval lon_reverse = point.lon - lon_half(point.lat < lat_half, point.lon < lon_half) match {// 右上角 , p1,p2 不需要動,需要動的是邊界和case (false, false) =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), bounds._2), maxLevel - 1) + 2 * Math.pow(4, maxLevel - 2).toInt//TODO: 問題// 右下角 向左旋轉// 此處需要也對point 點進行旋轉嗎?,好像不需要,這里是沿著中軸線旋轉180度case (false, true)  =>recursiveHilbertEncode(Point(lat_half - lon_reverse,lon_half - lat_reverse), ((Point(lat_half,bounds._1.lon),Point(bounds._2.lat,lon_half))), maxLevel - 1) + 3 * Math.pow(4, maxLevel-2).toInt//左上case (true, false)  =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), Point(bounds._1.lat,bounds._2.lon)), maxLevel - 1 ) +   Math.pow(4, maxLevel-2).toInt//TODO: 左下角也有問題// 左下角 向右旋轉case (true, true)   =>recursiveHilbertEncode(Point(lat_half + lon_reverse,lon_half + lat_reverse),   (bounds._1, Point(lat_half, lon_half)),maxLevel - 1)}}// 第一步函數:獲取瓦片編碼def getTileCode(p1: Point, p2: Point, bounds: (Point, Point), maxLevel: Int): Int = {// TODO:此處也默認 bounds 第一個點位于左下角// TODO: 此處默認p1 位于p2的左下角// 定義中心點 x,y值val x_half = (p1.lat + p2.lat)/2val y_half = (p1.lon + p2.lon)/2// 邊界的中心點val encoder = recursiveHilbertEncode(Point(x_half,y_half), bounds, maxLevel)encoder}/*** 測試左下角的16個區域* @param args*/def main2(args: Array[String]): Unit = {val bounds = (Point(10.0, 10.0), Point(20.0, 20.0))val maxLevel4 = 4// TODO: 左下角//  15 Error//     最左下角的四個,但是此時如果是旋轉過,再去查看右上角和左下角,就會有旋轉問題
//val p1 = Point(10,10)val p2 = Point(11.25,11.25)val tileCode0 = getTileCode(p1,p2,bounds,maxLevel4)println(s"TIle Code0 is given region :$tileCode0")val p3 = Point(10,11.25)val p4 = Point(11.25,12.5)val tileCode1 = getTileCode(p3,p4,bounds,maxLevel4)println(s"TIle Code1 is given region :$tileCode1")val p5 = Point(11.25,11.25)val p6 = Point(12.5,12.5)val tileCode2 = getTileCode(p5,p6,bounds,maxLevel4)println(s"TIle Code2 is given region :$tileCode2")val p7 = Point(11.25,10)val p8 = Point(12.5,11.25)val tileCode3 = getTileCode(p7, p8, bounds, maxLevel4)println(s"TIle Code3 is given region :$tileCode3")println("==================")val a = Point(12.5,10)val b = Point(13.75,11.25)val tileCode4 = getTileCode(a, b, bounds, maxLevel4)println(s"TIle Code4 is given region :$tileCode4")val t1 = Point(13.75,10)val t2 = Point(15.0, 11.25)val tileCode5 = getTileCode(t1,t2,bounds,maxLevel4)println(s"Tile Code5 is given region:$tileCode5")val c = Point(13.75,11.25)val d = Point(15,12.5)val tileCode6 = getTileCode(c,d,bounds,maxLevel4)println(s"TIle Code6 is given region :$tileCode6")val b3 = Point(12.5,11.25)val b4 = Point(13.75,12.5)val tileCode7 = getTileCode(b3,b4,bounds,maxLevel4)println(s"TIle Code7 is given region :$tileCode7")println("=================")val e = Point(12.5 ,12.5)val f = Point(13.75, 13.75)val tileCode8 = getTileCode(e,f,bounds,maxLevel4)println(s"TIle Code8 is given region :$tileCode8")val g = Point(13.75, 12.5)val h = Point(15,13.75)val tileCode9 = getTileCode(g, h,bounds, maxLevel4)println(s"TIle Code9 is given region :$tileCode9")val c3 = Point(12.5,13.75)val c4 = Point(13.75,15)val tileCode11 = getTileCode(c3,c4, bounds, maxLevel4)println(s"TIle Code11 is given region :$tileCode11")
//     左下角的左上角的右上角有問題println("==========")val c1 = Point(11.25,13.75)val c2 = Point(12.5,15)val tileCode12 = getTileCode(c1,c2,bounds,maxLevel4)println(s"TIle Code12 is given region :$tileCode12")val d1 = Point(11.25,12.5)val d2 = Point(12.5,13.75)val tileCode13 = getTileCode(d1,d2,bounds,maxLevel4)println(s"TIle Code13 is given region :$tileCode13")val d3 = Point(10,12.5)val d4 = Point(11.25,13.75)val tileCode14 = getTileCode(d3,d4,bounds,maxLevel4)println(s"TIle Code14 is given region :$tileCode14")val d5 = Point(10,13.75)val d6 = Point(11.25,15)val tileCode15 = getTileCode(d5,d6,bounds,maxLevel4)println(s"TIle Code15 is given region :$tileCode15")// TODO; 右下角TODO Error// 58
//    val p74 = Point(15,10)
//    val p84 = Point(16.25,11.25)
//    val tileCode44 = getTileCode(p74, p84, bounds, maxLevel4)
//    println(s"Tile Code for given region: $tileCode44")}def main(args: Array[String]): Unit = {val bounds = (Point(10.0, 10.0), Point(20.0, 20.0))// 右上角  42val p14 = Point(18.75, 18.75)val p24 = Point(20, 20)val maxLevel4 = 4val tileCode14 = getTileCode(p14, p24, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode14")// 左上角 //21val p34 = Point(10, 18.75)val p44 = Point(11.25, 20)val tileCode24 = getTileCode(p34, p44, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode24")//   5val p54 = Point(13.75, 10)val p64 = Point(15, 11.25)val tileCode34 = getTileCode(p54, p64, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode34")// TODO 15 Errorval p545 = Point(10, 13.75)val p645 = Point(11.25, 15)val tileCode344 = getTileCode(p545, p645, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode344")// 右下角// TODO Error// 58val p74 = Point(15,10)val p84 = Point(16.25,11.25)val tileCode44 = getTileCode(p74, p84, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode44")// 34val p1 = Point(16.25, 16.25)val p2 = Point(17.5, 17.5)val maxLevel = 3val tileCode = getTileCode(p1, p2, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode")// 10val p3 = Point(13.75, 13.75)val p4 = Point(15.0, 15.0)val tileCode2 = getTileCode(p3, p4, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode2")// 8val p5 = Point(12.5, 12.5)val p6 = Point(13.75, 13.75)val tileCode3 = getTileCode(p5, p6, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode3")// 32val p7 = Point(15.0, 15.0)val p8 = Point(16.25, 16.25)val tileCode4 = getTileCode(p7, p8, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode4")}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41416.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41416.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41416.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【fastadmin開發實戰】經營數據自動識別錄入

項目場景描述&#xff1a;每日錄入各個門店的員工經營數據&#xff0c;直接從微信復制報數、系統識別錄入。 解決方案&#xff1a;各個門店按照固定的匯報模板進行匯報&#xff08;如福田店有員工1、2、3、4、5號員工&#xff0c;每個員工按模板報數&#xff09; 例如&#xf…

Qt學習:Qt窗口組件以及窗口類型

一、Qt的窗口組件有哪些 Qt是一個跨平臺的C應用程序開發框架&#xff0c;它的窗口組件&#xff0c;也稱為用戶界面元素&#xff0c;為開發者提供了豐富的可視化界面設計選項。在Qt中&#xff0c;窗口組件主要包括&#xff1a; 窗口&#xff08;Window&#xff09;&#xff1a;…

JMH320【親測】【御劍九歌】唯美仙俠手游御劍九歌+WIN學習手工端+視頻教程+開服清檔+運營后臺+授權GM物品充值后臺

資源介紹&#xff1a; 這也是仙夢奇緣的一個游戲 注意&#xff1a;外網14位IP或域名 ———————————————————————————————————– ps后臺介紹: 1區運營后臺&#xff1a;http://ip:9981/admin/admintool/ 2區運營后臺&#xff1a;http://ip…

Day44:LeedCode 188.買賣股票的最佳時機IV 309.最佳買賣股票時機含冷凍期 714.買賣股票的最佳時機含手續費

188. 買賣股票的最佳時機 IV 給你一個整數數組 prices 和一個整數 k &#xff0c;其中 prices[i] 是某支給定的股票在第 i 天的價格。 設計一個算法來計算你所能獲取的最大利潤。你最多可以完成 k 筆交易。也就是說&#xff0c;你最多可以買 k 次&#xff0c;賣 k 次。 注意&…

[深度學習]卷積理解

單通道卷積 看這個的可視化就很好理解了 https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md 多通道卷積 當輸入有多個通道時,卷積核需要擁有相同的通道數. 假設輸入有c個通道,那么卷積核的每個通道分別于相應的輸入數據通道進行卷積,然后將得到的特征圖對…

51單片機STC89C52RC——14.1 直流電機調速

目錄 目的/效果 1&#xff1a;電機轉速同步LED呼吸燈 2 通過獨立按鍵 控制直流電機轉速。 一&#xff0c;STC單片機模塊 二&#xff0c;直流電機 2.1 簡介 2.2 驅動電路 2.2.1 大功率器件直接驅動 2.2.2 H橋驅動 正轉 反轉 2.2.3 ULN2003D 引腳、電路 2.3 PWM&…

智能光伏開發都能用到什么軟件和工具?

隨著全球對可再生能源的日益重視和光伏技術的快速發展&#xff0c;智能光伏開發已成為推動能源轉型的重要力量。在光伏項目的全生命周期中&#xff0c;從設計、建設到運營管理&#xff0c;各種軟件和工具的應用發揮著至關重要的作用。 一、光伏系統設計軟件 1、PVsyst PVsyst…

Linux 端口

什么是虛擬端口 計算機程序之間的通訊&#xff0c;通過IP只能鎖定計算機&#xff0c;但是無法鎖定具體的程序。通過端口可以鎖定計算機上具體的程序&#xff0c;確保程序之間進行溝通。 IP地址相當于小區地址&#xff0c;在小區內可以有許多用戶&#xff08;程序&#xff09;&…

java并發編程 JUC-基礎篇 快速入門

1.進程與線程的概念 &#xff08;1&#xff09;進程 程序有指令與數據組成&#xff0c;指令要運行&#xff0c;數據要讀寫&#xff0c;就必須指令加載到CPU。數據加載到內容&#xff0c;指令運行需要用到磁盤。 當一個程序被運行時&#xff0c;從磁盤加載這個程序的代碼至內…

探索Vue Router:構建高效單頁面應用的指南

引言 Vue Router&#xff0c;作為Vue.js的官方路由管理器&#xff0c;為構建SPA提供了強大的支持 Vue Router 基礎 Vue Router 的基本概念和作用 Vue Router 是一個用于構建單頁面應用的 Vue.js 插件。它允許我們通過定義路由規則來將不同的 URL 映射到不同的組件&#xff…

1023記錄

米哈游二面 自動化測試中自動化驅動的能力&#xff1f; pytest的驅動能力&#xff1a; 1&#xff0c;自動發現測試用例&#xff1a;以"test_"開頭的Python文件、以"Test"開頭的類和以"test_"開頭的函數&#xff0c;將它們識別為測試用例 2&…

植物大戰僵尸融合版最新版1.0下載及安裝教程

《植物大戰僵尸融合版》最新版1.0已經發布&#xff0c;為粉絲們帶來了全新的游戲體驗。這個版本由B站UP主藍飄飄fly精心打造&#xff0c;引入了創新的植物融合玩法&#xff0c;讓玩家可以享受策略和創意的結合。以下是游戲的詳細介紹和安裝指南&#xff1a; 游戲特色介紹 全新…

基于深度學習的圖像背景剔除

在過去幾年的機器學習領域&#xff0c;我一直想打造真正的機器學習產品。 幾個月前&#xff0c;在參加了精彩的 Fast.AI 深度學習課程后&#xff0c;似乎一切皆有可能&#xff0c;我有機會&#xff1a;深度學習技術的進步使許多以前不可能實現的事情成為可能&#xff0c;而且開…

Java--繼承

1.繼承的本質是對某一批類的抽象&#xff0c;從而實現對世界更好的建模 2.extends的意思是“擴展”&#xff0c;子類是父親的擴展 3.Java中只有單繼承&#xff0c;沒有多繼承 4.繼承關系的兩個類&#xff0c;一個為子類&#xff08;派生類&#xff09;&#xff0c;一個為父類…

QML-Grid和OpacityMask

一個格子條&#xff0c;點擊縮短 import QtQuick 2.0 import QtQuick.Window 2.12 import QtQuick.Controls 2.5 //導入 import QtGraphicalEffects 1.12Window {id:windowwidth: 600height: 500color: "white"visible: trueGrid {visible: falseid:gridwidth:405he…

STAR 命令參數解釋

以這個為例子解釋STAR參數含義 STAR 命令參數解釋 STAR \ --outFilterType BySJout \ --runThreadN 8 \ --outFilterMismatchNmax 2 \ --genomeDir <hg19_STARindex> \ --readFilesIn <un_aligned.fastq> \ --outFileNamePrefix <HEK293> \ --outSAMtype B…

歐科云鏈大咖對話:Web3原生創新靜默期,科技巨頭卻在兩極化發展

出品&#xff5c;OKG Research 作者&#xff5c;Hedy Bi 上周末&#xff0c;歐科云鏈研究院接受FT中文的邀請&#xff0c;作為圓桌嘉賓參與了由FT中文網與上海交通大學上海高級金融學院聯合主辦的金融大師課。在圓桌環節&#xff0c;筆者與各位教授和金融行業科技創新前沿實踐…

案例精選 | 聚銘網絡助力南京市玄武區教育局構建內網日志審計合規體系

南京市玄武區教育局作為江蘇省教育領域的先鋒機構&#xff0c;其工作重點涵蓋了教育政策的實施、教育現代化與信息化的融合、教育資源的優化、教育質量的提升以及教育公平的促進。在這一背景下&#xff0c;網絡安全管理成為了確保教育信息化順利推進的關鍵環節之一。 根據玄武…

Nacos單機部署、集群部署以及Nacos默認持久化derby數據庫和配置mysql數據庫

1. Nacos Windows 下載 1.1 去nacos官網下載nacos-server 發布歷史 | Nacos 官網https://nacos.io/download/release-history/ 下載版本為 nacos-server-2.3.1.zip 2. Derby數據庫 2.1 默認使用Derby數據庫 官網下載Derby數據庫即可。 Apache Derby數據庫https://db.apac…

昇思25天學習打卡營第9天|MindSpore使用靜態圖加速(基于context的開啟方式)

在Graph模式下&#xff0c;Python代碼并不是由Python解釋器去執行&#xff0c;而是將代碼編譯成靜態計算圖&#xff0c;然后執行靜態計算圖。 在靜態圖模式下&#xff0c;MindSpore通過源碼轉換的方式&#xff0c;將Python的源碼轉換成中間表達IR&#xff08;Intermediate Repr…