[Python教學]利用Python操作KMZ壓縮檔並進行批次平移坐標

#Python #解壓縮 #KMZ修改坐標

對於測量從業人員來˙說,對於KML或KMZ檔案應該是很熟悉的,其中KMZ檔案是KML檔案的壓縮檔形式,簡單的應用場景來說KML資料只需要單一檔案就可以完整呈現點位標記了,但如果今天需要針對KML檔案附加Javascript腳本,或是想要附加圖片資訊則需要將檔案進行整合壓縮成KMZ方便攜帶,例如筆者先前介紹過的利用相片EXIF檔將坐標資訊轉換到寫入KML並可以在Google Earth同時瀏覽照片。

[Python教學]利用Python解壓縮KMZ批次平移坐標

由於KMZ檔案屬於壓縮檔案的一種,因此同樣可以利用7-zip或是Win-RAR進行解壓縮處理筆者在處理PS-InSAR資料時,測量點位進行地理對位時容易受到高度影響因此產生偏移,這時候可以利用Python進行解壓縮並寫入人工校正值。

利用7-zip解壓縮KMZ檔案
利用7-zip解壓縮KMZ檔案

Python壓縮檔操作- Zipfile模組

Python中有許多可以操作壓縮檔的模組工具,其中Zipfile是Python初始安裝時就附帶的內建模組了,這邊就採用Zipfile進行壓縮檔操作說明。

Zipfile模組匯入並讀取KMZ檔案

import zipfile
ZIP = zipfile.ZipFile(r"\SAR工具\0927.kmz") #這邊選擇KMZ檔案的路徑進行讀取 # r符號可以轉譯斜線'\'
ZIP.namelist() #透過namelist() 可以讀取壓縮檔中的檔案

透過讀取KMZ檔案,可以發現其檔案組成包括了.kml 以及 js. 和 .png檔案

讀取KMZ顯示檔案列表
讀取KMZ顯示檔案列表

解壓縮KMZ檔案到指定資料夾

接下來可以透過 ZIP.extractall() 函式,將KMZ檔案進行解壓縮到指定資料夾中

import zipfile
ZIP = zipfile.ZipFile(r"SAR工具\0927.kmz") #這邊選擇KMZ檔案的路徑進行讀取
ZIP.namelist() #透過namelist() 可以讀取壓縮檔中的檔案
ZIP.extractall('./temp/') #將KMZ壓縮檔解壓縮至當前資料夾的 ./temp 中
ZIP.close() #關閉檔案 釋放檔案佔用

KMZ解壓縮後的資料夾
KMZ解壓縮後的資料夾

修改指定KML檔案的坐標資訊

對於筆者本次要進行的修改的坐標資訊儲存檔案是「0927_lev0_1.kml」因此我們要額外載入處理XML檔案的模組,以下簡單透過註釋說明如何進行坐標偏移修改

from pykml import parser #用於解析kml檔案
from lxml import etree  #用於寫入kml檔案
kml_file=r".\temp\0927_dir\0927_lev0_1.kml" #要處理的kml
with open(kml_file,'r') as f: #讀取kml檔案
    doc = parser.parse(f).getroot() #獲取kml檔案根內容
    for placemark in doc.Document.Placemark: #對於每個點位其內容資料儲存在doc.Document.Placemark中
        coordinates = placemark.Point.coordinates.text.strip() #坐標資訊存位置,並透過strip()去除空白
        old_longitude, old_latitude, altitude = [float(i) for i in coordinates.split(',')]
        #此處修改坐標偏移 例如以西移0.00020度,北移0.0009度
        new_coordinates = f"{old_longitude-0.00020},{old_latitude+0.0009},{altitude}"
        placemark.Point.coordinates = new_coordinates #重新寫入新坐標
    with open(kml_file, 'wb') as f: #透過修改過後的doc資訊重新寫入新檔案
        content = etree.tostring(etree.ElementTree(doc),pretty_print=True)
        f.write(content)

重新壓縮temp資料夾檔案成為KMZ檔

修改完成坐標資訊後,可以繼續透過Zipfile將 ./temp 資料夾中的檔案進行重新壓縮成KMZ檔,透過zipfile.ZipFile() 可以創建新的壓縮檔案並指定檔案路徑,mode=’w’ 表示寫入新檔案,如果有檔案已存在則會進行覆蓋,os.walk則會針對資料夾內的檔案進行遞迴找尋接下來透過 zf.write() 將所有檔案進行加速壓縮檔,shutil.rmtree()則可以將./temp進行刪除

import os 
import shutil
#創建新的kmz壓縮檔
with zipfile.ZipFile(f'./result/0927.kmz', mode='w') as zf: 
    #透過os.walk進行資料夾遍歷
    for root, dirs, files in os.walk("./temp/", topdown=False):
        for name in files:
            #filenmae代表來源資料路徑 arcname則是壓縮檔內的檔案名稱路徑,這邊透過replace操作去除./temp路徑
            zf.write(filename=os.path.join(root, name),arcname=os.path.join(root.replace('./temp/','.//'),name))
#刪除暫除資料夾
shutil.rmtree('./temp/')

KMZ檔案修改前後對比

接下來就可以比對我們修改KMZ坐標前後的成果同時對於該KMZ的.JS執行和.PNG讀取保持正常運作

修改前的點位坐標
修改前的點位坐標
修改後的點位坐標
修改後的點位坐標
KMZ中的.js檔案正常運作
KMZ中的.js檔案正常運作
分享