Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Python/Javascriptで読む点群
Search
Taro Matsuzawa aka. btm
November 08, 2020
Programming
5.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Python/Javascriptで読む点群
FOSS4G 2020 Japan Online
Taro Matsuzawa aka. btm
November 08, 2020
More Decks by Taro Matsuzawa aka. btm
See All by Taro Matsuzawa aka. btm
OpenLayers ext TypeScript declarationの開発
smellman
0
660
平成生まれのためのUNIX&IT歴 史講座 ~番外編~
smellman
2
590
掛川城の点群データをiTownsで表示しよう
smellman
0
360
そのJavascript、全部TypeScriptにしちゃえ
smellman
1
270
大容量SSDとOpenStreetMap
smellman
0
180
MapLibreとtile.openstretmap.jpで始めるベクトル地図プログラミング
smellman
1
670
国内向けタイルサーバの構築と運用について
smellman
0
1.8k
日本のCommunity向け タイルサーバの現状
smellman
0
2.8k
Pythonで点群を読んでみよう
smellman
1
2.9k
Other Decks in Programming
See All in Programming
Flow は今どうなっているか
mizdra
PRO
0
710
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
280
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
550
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
リアルな遅延を測る仕様
kota_yata
1
130
Press start. Python's next generation.
willingc
PRO
3
130
ソフトウェアエンジニアにとっての生成AI - 特性を知って使い倒す / generative ai for software enginner
kishida
7
2.1k
FastAPI の並行処理モデルを完全に理解する
hoto17296
8
3k
Go 1.27からのGODEBUG / Go 1.27 リリースパーティ #go127party
mazrean
0
220
Discordを用いたラボオートメーション関連情報収集の自動化
noguhiro2002
0
440
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
230
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.7k
Featured
See All Featured
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.4k
Paper Plane (Part 1)
katiecoart
PRO
1
10k
The Invisible Side of Design
smashingmag
301
52k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.8k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
470
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Building an army of robots
kneath
306
46k
For a Future-Friendly Web
brad_frost
183
10k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.3k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Being A Developer After 40
akosma
91
590k
Transcript
FOSS4G 2020 Japan Online 松澤太郎 Python/Javascriptで 読む点群
自己紹介
タイル三兄弟の一味 Twitter: @smellman Georepublic シニアデベロッパ、日本UNIXユーザ会理事、OSGeo日本支部理事、 OpenStreetMap Foundation Japanメンバー React NativeとかRuby
on RailsとかPythonとかやってる地理系プログラマー ブレイクコアクラスタ 自己紹介
A Location Technology Company
None
None
Open Source GISを得意とする会社 東京、神戸、ミュンヘンにオフィスがあります 神戸オフィスはちょっとエモいので神戸に来たら遊びに来るといいよ さまざまな国や地域のエンジニアが参加 お仕事待ってます(^^ Georepublic
弊社社長が政府CIO補佐官に 政府がハックされる事態に 乞うご期待! News
バイナリの読み方は仕様がわかっていれば(比較的)簡単 (比較的)簡単であることさえ知られてないのでは? 簡単なフォーマットから始めればいろいろ応用が効く バイナリが読めれば書けるようにもなる オレオレVector Tileなんかも作れちゃう(俺は作ったことがある) なぜバイナリを読む?
点群とは(さくっと) Pythonで読む https://github.com/smellman/python_lasreader_example Javascriptで読む https://github.com/smellman/javascript_lasreader_example 今日のお題
点群とは
地理で使われるデータの一種 レーザー測量やSfMなどで得られたPoint Data群 Point Cloudという 3Dでの地図表現でよく使われるデータ 最近では自動運転とかSmartうんたらかんたら 点群とは https://tiles.smellman.org/kakegawa/index-itowns.html
las(LASer format)及びlaz(zip圧縮したもの)が有名 lasの仕様書は公開されている https://www.asprs.org/wp-content/uploads/2010/12/LAS_1_4_r13.pdf las1.2〜1.4が一般的に使われている バージョンの違いはヘッダー及び扱えるものの差 フォーマット
Potree 独自のストラクチャを持つもの。専用のコンバータ PotreeConverter を使う。 一時期PotreeConverterが商用ソフトになった(現在はBSDライセンス)。 Cesium or iTown or giro3d
3D Tiles に対応。OSSのコンバータでは entwine か py3dtiles が有名。 点群を表示するWebライブラリ
lasデータは仕様が公開されている 静岡県がlasデータをたくさん公開している Creative Commons License 4.0 バイナリを読むプログラムを書くのに良い題材となる 今回はヘッダーを読むプログラムを見て雰囲気を掴んでほしい 今回の本題
Pythonで読む
Pythonに限らずだいたいのプログラミング言語には標準でバイナリを読むモジュールがある Pythonの場合 struct を利用する https://docs.python.org/ja/3/library/struct.html Pythonで読む
lasの仕様書を手元に置きます import struct をします open(file_path, ‘rb’) でファイルを開きます rb = read
only, binary structで一つずつ読み込んでいきます 読み方
こんな感じのコードになります 先頭を読む import struct f = open(‘your.las’, ‘rb’) file_signature =
b"".join(list(struct.unpack('4c', f.read(1*4)))).decode(‘ascii') print(file_signature) f.close() # 閉じておく
こんな感じのコードになります File Source IDを読む import struct f = open(‘your.las’, ‘rb’)
file_signature = b"".join(list(struct.unpack('4c', f.read(1*4)))).decode(‘ascii') (file_source_id,) = struct.unpack(‘H’, f.read(2)) print(file_source_id) f.close() # 閉じておく tupleで返ってくるので注意
f.read関数はファイルを読む開始位置をずらしていきます 例えば二回f.readを使うと… f.read(4) f.read(3) 開始位置が7へ移動する read関数 read(4) 0 read(3) N
struct.unpackで読んだバイナリをどのようにアサインするかを決める struct.unpack('4c', f.read(1*4)) char[4] struct.unpack('<L', f.read(4)) unsinged long (リトルエンディアン) struct.unpack
Lasのフォーマットのドキュメントを読みながらひたすらstruct.unpackを並べていく 随時printするなりして問題ないかチェックする unit testを書いても良い わりと単純にPythonでは読むことができる 逆を言うとJavascriptはクセがすごい あとは突き合わせをしていく
こんな感じになる def header(self, f): file_signature = b"".join(list(struct.unpack('4c', f.read(1*4)))).decode('ascii') (file_source_id,) =
struct.unpack('H', f.read(2)) (global_encoding,) = struct.unpack('H', f.read(2)) (guid_data1,) = struct.unpack('<L', f.read(4)) (guid_data2,) = struct.unpack('H', f.read(2)) (guid_data3,) = struct.unpack('H', f.read(2)) guid_data4 = struct.unpack('<8B', f.read(1*8)) …
LASのversion minorによってヘッダの大きさが変わる LAS 1.2 -> 227byte LAS 1.3 -> 235byte
LAS 1.4 -> 375byte 必ずversion checkを入れること 読む上で注意点
ヘッダーにOffset to point dataという値があるので、ここに f.seek をして読み始める データそのものの読み方も仕様を読みながら。 実際の値はscale factorとoffsetの組み合わせになるとかもちゃんと仕様に書いてあるの で見逃さないこと。
点群そのものを読む
Javascriptで読む
今回はFile APIとFileReader APIを利用 ブラウザからファイルを読み込む用途を想定 時間があればデモします https://smellman.github.io/javascript_lasreader_example/ Javascriptで読む
FileReader APIにイベントハンドラを作成します blobファイルをsliceしたものをFileReader APIで読みます 次のoffsetを指定してまたsliceしてFileReader APIで読みます 次の(ry 読み方
sliceで読み取る範囲を指定して readAsArrayBufferで読み取る onloadイベントハンドラが読みとっ て、またreadAsArrayBufferを呼び 出して… イベントハンドラがバイナリを読 む責務を追っている 最後はreader.abort()をする ややこしい class
LasReader { constructor(blob) { this.blob = blob } read(callback) { let offset = 0 let reader = new FileReader() let slice = this.blob.slice(offset, 4) reader.onload = (e) => { if (offset == 0) { const file_signature = char_to_string(e.target.result) console.log(`file_signature: ${file_signature}`) offset = 4 slice = self.blob.slice(offset, 6) } else if (offset == 6) { … } else { reader.abort() // call reader.onloaded } reader.readAsArrayBuffer(slice) } reader.onloaded = () => { callback(…) } reader.readAsArrayBuffer(slice) // 開始 } }
こういう構造のケースはPromiseを使うと簡単に書くことができます async/await を使えばPythonっぽく書くこともできます Promiseを使おう
offsetとreaderをthisで参照可能に する onloadのときにresolveを呼ぶ sliceを作るサイズを引数にして、成 功時にoffsetに加算する Promise class LasParser { constructor(blob)
{ this.blob = blob this.offset = 0 this.reader = new FileReader() } readSlice(size) { return new Promise((resolve, reject) => { this.reader.onload = (e) => { this.offset += size resolve(e.target.result) } this.reader.onerror = (e) => { console.log('onerror') reject(e) } const slice = this.blob.slice(this.offset, this.offset + size) this.reader.readAsArrayBuffer(slice) }) }
async/await async read(target, callback) { let result = await this.readSlice(4)
const file_signature = char_to_string(result) result = await this.readSlice(2) const file_source_id = (new DataView(result)).getUint16() result = await this.readSlice(2) const global_encording = (new DataView(result)).getUint16(0, true) result = await this.readSlice(4) const guid_data1 = (new DataView(result)).getUint32(0, true) … const z = new DataView(result) const max_z = z.getFloat64(0, true) const min_z = z.getFloat64(8, true) this.reader.abort() callback(max_x, min_x, max_y, min_y) } await this.readSlice で何バイト読 むか指定 読まれたバイナリの処理の責務が すべてread関数になる 最後はthis.reader.abort()を実行 してcallbackを呼ぶ
DataViewなどの処理をするところが外だしできる Promiseを使わないとイベントハンドラ内なのでthisを使いまくるしかない Promiseを使えば変数はほぼconstで指定できるので安心できる letを使うのは一箇所ぐらい ヘッダ以外にもoffsetをずらせばbodyも簡単に読めるよ! Promiseの良いところ
Pythonではstructを使うと簡単にバイナリが読めるよ JavascriptはクセがあるけどPromise/async/awaitを使えば簡単に読めるよ 今回作ったプログラム(Las 1.2まで) https://github.com/smellman/python_lasreader_example https://github.com/smellman/javascript_lasreader_example まとめ