TIF转换到KMZ的教程

KML 和 KMZ 都是 Google 地球和其他地图程序中用于显示地理数据的文件格式。两者之间的主要区别在于,KML 是一种用于以 XML 格式存储地理数据的文件格式,而 KMZ 是一种压缩文件格式,包含一个或多个 KML 文件及其关联资源。

阅读本文,了解有关 KML 和 KMZ 的更多信息以及它们之间的区别。

什么是 KML?

KML(Keyhole 标记语言)是一种用于在三维空间中显示地理数据的文件格式,通常在 Google 地球等虚拟地球仪上显示。它是一种基于 XML 的语言,允许您构建和显示结构化地理信息。

例如,点由其纬度、经度和(可选)高度定义,并指示地图上的特定位置。地图上的线条和多边形描绘路径或区域,并由一组定义其形状的坐标定义。使用“扩展数据”元素,可以将名称、描述和 URL 等描述性信息链接到这些地理元素。

以下是 KML 的一些关键功能和组件 -

  • 地理特征- KML 可以定义众多地理元素,例如点、线、多边形和 3D 模型。这些功能可以显示在虚拟地球上,您可以使用名称、描述和照片对其进行自定义。
  • 样式- 在 KML 中,您还可以设置地理特征的样式。您可以更改线条的颜色和粗细,以及多边形的不透明度和纹理。这使您的数据更具视觉吸引力且易于理解。
  • 叠加图像- 您还可以使用 KML 将图像叠加在地理数据之上。这非常适合添加上下文或视觉信息,例如卫星照片或历史地图。
  • 基于时间的数据- KML 还允许基于时间的数据,因此您可以看到事物如何随时间变化。每个功能都可以分配一个时间段并按时间顺序显示。这可以用来描述天气模式、人口扩张或物品移动的变化。
  • 网络链接- KML 还支持网络链接,即指向外部 KML 文件或互联网资源的链接。这使您能够创建不断更新的动态和交互式地图。要显示当前天气状况,您可以建立指向在线天气服务的网络链接。

KML 是一种复杂的文件格式,用于以结构化且具有视觉吸引力的方式创建和显示地理数据。 KML 经常用于环境监测、城市规划和旅游等应用,因为它支持不同的地理元素、风格选项、叠加图像、基于时间的数据和网络链接。

KMZ是什么?

KMZ(Keyhole 标记语言压缩)是一种压缩文件格式,用于存储地理数据,包括 KML 文件以及与其相关的资源,例如照片、图标和其他文件。 Keyhole Inc.(2004 年被 Google 收购)将其创建为一种在单个文件中捆绑和传输大量地理数据的机制。

KMZ 文件是通过将一个或多个 KML 文件及其相关资源压缩到一个扩展名为“.kmz”的文件中而形成的。压缩可以减小文件大小,从而更容易通过互联网共享和下载。当您在地图应用程序中打开 KMZ 文件时,KML 文件和关联资源将被提取并显示在地图上。

KMZ 文件可以包含与 KML 文件相同类型的地理数据,例如点、线、多边形和其他形状,以及描述性数据,例如名称、描述和 URL。区别在于,KMZ 文件包含显示数据所需的任何附带资源,例如图像和图标,从而形成一个可以轻松共享的独立包。

除了地理数据之外,KMZ 文件还可以包含样式、屏幕覆盖和网络链接等功能。样式允许您自定义地理数据的外观,而屏幕覆盖允许您在地图上显示图像或文本。其他 KML 或 KMZ 文件以及在线数据源可以通过网络链接引用。

总体而言,KMZ是一种实用且有效的打包和共享海量地理数据的方法,广泛应用于测绘、GIS和环境监测等一系列应用中。

KML 和 KMZ 之间的区别

下表强调了 KML 和 KMZ 之间的主要区别 -

特征 克米勒 克麦兹
定义 KML 是一种用于以 XML 格式存储地理数据的文件格式。 KMZ 是一种压缩文件格式,包含一个或多个 KML 文件及其关联资源。
文件格式 它是一种基于 XML 的文件格式。 它是一种压缩 (Zip) 文件格式。
数据内容 地理数据 地理数据和资源
文件扩展名 .kml .kmz
文件大小 由于包含资源,KML 文件大小较大。 由于压缩,KMZ 文件大小很小。
分享 在 KML 中,共享是通过电子邮件、文件共享平台或直接下载完成的。 在 KMZ 中,共享是通过电子邮件、文件共享平台或直接下载来完成的。
代表 锁孔标记语言 (KML) 压缩锁孔标记语言 (KMZ)
用法 KML 用于存储地理数据。 KMZ 文件用于打包 KML 文件并与关联资源共享。

20240516

KML(Keyhole Markup Language)和SHP(Shapefile)都是用于表示地理数据的文件格式,但它们在设计和应用上有一些差异。说KML是SHP的“更先进版本”可能并不完全准确,因为这两种格式各有其优点和适用场景。然而,KML在某些方面确实具有一些独特的优势,这些优势可能使其在某些应用中表现得更为“先进”。

以下是KML相对于SHP的一些优势:

  1. 跨平台兼容性:KML是一种基于XML的开放标准,因此它可以在各种操作系统和平台上使用,包括Web浏览器、移动设备和桌面应用程序。这使得KML成为一种非常灵活的地理数据格式,可以轻松地在不同的系统和应用程序之间共享和交换数据。
  2. 丰富的可视化功能:KML支持丰富的可视化功能,包括自定义图标、线条颜色、填充颜色、文本标签等。这使得KML可以创建出具有高度可定制性和吸引力的地图和地理可视化效果。
  3. 时间和动画支持:KML支持时间相关的地理信息,可以使用户展示地理位置随时间变化的动画效果。这对于描述历史轨迹、飞行路径等应用非常有用。
  4. 广泛的应用程序支持:KML是Google Earth和其他许多地理信息系统(GIS)应用程序的标准格式之一。这使得KML具有广泛的应用程序支持,并且可以与许多流行的GIS工具无缝集成。

相比之下,SHP格式在以下方面有一些限制:

  1. 封闭性:SHP是由ESRI公司开发的专有格式,因此其使用可能受到某些限制。例如,它可能不如KML那样易于在不同的系统和应用程序之间共享和交换数据。
  2. 可视化功能有限:虽然SHP格式支持基本的地理数据可视化,但它可能不如KML那样灵活和可定制。
  3. 应用程序支持有限:尽管SHP格式在GIS行业中广泛应用,但它可能不如KML那样受到广泛支持。某些GIS应用程序可能不支持SHP格式,或者可能需要额外的插件或驱动程序才能支持它。

那SHP格式可以转换到KML格式么?

答案是可以的,请看以下python代码。

python
#!/usr/bin/env python
# -*- coding: utf-8 -*- 
# @Time : 2024/5/16 22:30
# @File : shp2kml.py

from osgeo import ogr
import os

def convert_to_kml(shapefile,outpath):
    ds = ogr.Open(shapefile)
    shape = ds.GetLayer(0)
    attribute_names = []
    ldefn = shape.GetLayerDefn()

    for n in range(ldefn.GetFieldCount()):
        fdefn = ldefn.GetFieldDefn(n)
        attribute_names.append(fdefn.name)
    boundary =''
    placemark = ''
    i = 1
    for obj in shape:
        placemark +='\n<Placemark id="ID_{}">' \
                    '\n<styleUrl>#m_ylw-pushpin</styleUrl>' \
                    '\n{}' \
                    '\n</Placemark>'.format(str(i),obj.GetGeometryRef().ExportToKML())
        i+=1




    constant = '<?xml version="1.0" encoding="UTF-8"?>' \
                   '<kml ' \
                   'xmlns="http://www.opengis.net/kml/2.2" ' \
                   'xmlns:atom="http://www.w3.org/2005/Atom" ' \
                   'xmlns:gx="http://www.google.com/kml/ext/2.2" ' \
                   'xmlns:kml="http://www.opengis.net/kml/2.2">' \
                   '<name>%s</name>' \
                   '\n<Document>' \
                   '\n<Style id="s_ylw-pushpin_hl"><IconStyle><scale>1.3</scale>' \
                   '\n<Icon><href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href></Icon>' \
                   '\n<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/></IconStyle>' \
                   '\n<LineStyle><color>ff0000ff</color><width>2</width></LineStyle>' \
                   '\n<PolyStyle><fill>0</fill></PolyStyle></Style>' \
                   '\n<StyleMap id="m_ylw-pushpin"><Pair><key>normal</key><styleUrl>#s_ylw-pushpin</styleUrl></Pair>' \
                   '\n<Pair><key>highlight</key><styleUrl>#s_ylw-pushpin_hl</styleUrl></Pair></StyleMap>' \
                   '\n<Style id="s_ylw-pushpin"><IconStyle><scale>1.1</scale>' \
                   '\n<Icon><href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href></Icon>' \
                   '\n<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/></IconStyle>' \
                   '\n<LineStyle><color>ff0000ff</color><width>2</width></LineStyle><PolyStyle><fill>0</fill>' \
                   '\n</PolyStyle></Style>'

    end_tag = '</Document></kml>'

    kml = ''.join([constant,  placemark, end_tag])

    # filler = '<Data name="{}"><value>{}</value></Data>'
    # closing_tag = '</ExtendedData>'
    #     # constant + filler + closing + end_tag
    # data = []
    # for attribute in attribute_names:
    #             data.append(filler.format(attribute, obj.GetField(attribute)))
    # data = ''.join(data)

    filename = os.path.basename(shapefile).split('.')[0]


    if not os.path.exists(outpath):
            os.makedirs(outpath)

    out_file = open(outpath+'\\'+filename+".kml", "w")
    out_file.write(kml)
    out_file.close()

if __name__ == '__main__':

    shapefile = r"D:\11.shp"
    outpath = r'D:\kml'
    convert_to_kml(shapefile, outpath)

考虑到部分朋友可能不会编程,现在把以上代码打包为exe命令行程序,作为一个特定功能的小工具分享给大家。

shell
pyinstaller -F -i favicon.png shp2kml.py

点要素kml在google earth 可视化

image-20240516161029967

线要素kml在google earth 可视化

image-20240516161131697

面要素kml在google earth 可视化

image-20240516161111943

20240612 ChatGPT

使用Python将GeoTIFF转换为KMZ文件

在地理信息系统(GIS)领域,GeoTIFF是一种常见的栅格数据格式,而KMZ是Google Earth使用的压缩KML格式。本文将介绍如何使用Python将GeoTIFF文件转换为KMZ文件。具体实现中,我们将使用GDAL库处理GeoTIFF文件,并利用Pillow库生成PNG图片,最后通过zipfile库将生成的KML和PNG文件打包成KMZ文件。

所需依赖库

首先,需要确保安装了以下Python库:

  • gdal:用于读取和处理GeoTIFF文件。
  • numpy:用于数组操作和数据处理。
  • Pillow:用于图像处理。
  • zipfile:用于创建和管理ZIP文件。
Code
pip install gdal numpy Pillow

实现步骤

1. 创建类tif2kmz

创建一个tif2kmz类,它包含所有转换过程的步骤。

Code
from zipfile import ZipFile
from osgeo import gdal
import codecs
import numpy as np
import PIL.Image as Image

class tif2kmz:
    def __init__(self, tif_file, kmz_file):
        self.tif_file = tif_file
        self.kmz_file = kmz_file

2.获取GeoTIFF文件的属性

定义一个方法get_attribute,用于获取GeoTIFF文件的地理属性,这些属性将在生成KML文件时使用。

python
def get_attribute(self):
    ds = gdal.Open(self.tif_file, gdal.GA_ReadOnly)
    gt = ds.GetGeoTransform()
    self.east_longitude = gt[0]
    self.west_longitude = self.east_longitude + (ds.RasterXSize * gt[1])
    self.north_latitude = gt[3]
    self.south_latitude = self.north_latitude + (ds.RasterYSize * gt[5])

3.图像线性拉伸

定义一个方法linear_stretch,对图像数据进行线性拉伸,以增强图像对比度。

python
def linear_stretch(self, data, num=1):
    data_8bit = data
    data_8bit[data_8bit == -9999] = 0

    d2 = np.percentile(data_8bit, num)
    u98 = np.percentile(data_8bit, 100 - num)

    maxout = 255
    minout = 0
    data_8bit_new = minout + ((data_8bit - d2) / (u98 - d2)) * (maxout - minout)
    data_8bit_new[data_8bit_new < minout] = minout
    data_8bit_new[data_8bit_new > maxout] = maxout
    data_8bit_new = data_8bit_new.astype(np.int32)
    return data_8bit_new

4.创建临时PNG文件

定义一个方法create_temp_png,将GeoTIFF文件转换为PNG格式的图片。

Code
def create_temp_png(self):
    ds = gdal.Open(self.tif_file, gdal.GA_ReadOnly)
    png_file = 'overlay.png'
    data = ds.ReadAsArray()
    z, x, y = data.shape
    temp_arr = np.zeros(shape=(x, y, 3))
    for i in range(3):
        temp_arr[:, :, i] = self.linear_stretch(data[i, :, :], 2)
    temp_arr = temp_arr.astype(np.uint8)
    img = Image.fromarray(temp_arr)
    img.save(png_file)

5. 创建KML文件

python
def create_kml(self):
    self.get_attribute()
    overlay_name = "KML overlay"
    kml = (
        '<?xml version="1.0" encoding="UTF-8"?>\n'
        '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
        '  <Folder>\n'
        '    <name>Ground Overlays</name>\n'
        '    <description>Examples of ground overlays</description>\n'
        '    <GroundOverlay>\n'
        '      <name>%s</name>\n'
        '      <Icon>\n'
        '        <href>overlay.png</href>\n'
        '      </Icon>\n'
        '      <LatLonBox>\n'
        '        <north>%f</north>\n'
        '        <south>%f</south>\n'
        '        <east>%f</east>\n'
        '        <west>%f</west>\n'
        '      </LatLonBox>\n'
        '    </GroundOverlay>\n'
        '  </Folder>\n'
        '</kml>\n'
    ) % (overlay_name, self.north_latitude, self.south_latitude, self.east_longitude, self.west_longitude)

    with codecs.open('overlay.kml', encoding='utf-8', mode='w+') as kmlFile:
        kmlFile.write(kml)

6.创建KMZ文件

定义一个方法create_kmz,将生成的KML文件和PNG文件压缩成KMZ文件。

python
def create_kmz(self):
    self.create_temp_png()
    self.create_kml()
    with ZipFile(self.kmz_file, 'w') as zipObj:
        zipObj.write('overlay.kml')
        zipObj.write('overlay.png')

7. 主函数

最后,在主函数中实例化tif2kmz类,并调用create_kmz方法。

python
if __name__ == '__main__':
    ql_image_filename = r'D:\test\DJI_20230410091240_0035.tif'
    kml_output_filename = r'D:\test\DJI_20230410091240_0035.kmz'
    tif2kmz = tif2kmz(ql_image_filename, kml_output_filename).create_kmz()

完整代码

python
from zipfile import ZipFile
from osgeo import gdal
import codecs
import numpy as np
import PIL.Image as Image


class tif2kmz:
    def __init__(self, tif_file, kmz_file):
        self.tif_file = tif_file
        self.kmz_file = kmz_file

    def get_arrtibute(self):
        # 获取tif文件的属性, 用于生成kml文件
        ds = gdal.Open(self.tif_file, gdal.GA_ReadOnly)
        gt = ds.GetGeoTransform()
        self.east_longitude = gt[0]
        self.west_longitude = self.east_longitude + (ds.RasterXSize * gt[1])
        self.north_latitude = gt[3]
        self.south_latitude = self.north_latitude + (ds.RasterYSize * gt[5])

    def linear_stretch(seld, data, num=1):
        '''

        @param data: 待拉伸的矩阵
        @param num: 拉伸系数,一般为1-5
        @return: 拉伸后的矩阵
        '''
        data_8bit = data
        data_8bit[data_8bit == -9999] = 0

        # 把数据中的nan转为某个具体数值,例如
        # data_8bit[np.isnan(data_8bit)] = 0
        d2 = np.percentile(data_8bit, num)
        u98 = np.percentile(data_8bit, 100 - num)

        maxout = 255
        minout = 0
        data_8bit_new = minout + ((data_8bit - d2) / (u98 - d2)) * (maxout - minout)
        data_8bit_new[data_8bit_new < minout] = minout
        data_8bit_new[data_8bit_new > maxout] = maxout
        data_8bit_new = data_8bit_new.astype(np.int32)
        return data_8bit_new
    def create_temp_png(self):
        ds = gdal.Open(self.tif_file, gdal.GA_ReadOnly)
        png_file = 'overlay.png'
        data = ds.ReadAsArray()
        z,x,y = data.shape
        temp_arr = np.zeros(shape=(x, y, 3))
        for i in range(3):
            temp_arr[:, :, i] = self.linear_stretch(data[i, :, :],2)
            print(i)
        temp_arr = temp_arr.astype(np.uint8)
        img = Image.fromarray(temp_arr)
        img.save(png_file)


    def create_kml(self):
        self.get_arrtibute()
        overlay_name = "KML overlay"
        kml = (
                  '<?xml version="1.0" encoding="UTF-8"?>\n'
                  '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
                  '  <Folder>\n'
                  '    <name>Ground Overlays</name>\n'
                  '    <description>Examples of ground overlays</description>\n'
                  '    <GroundOverlay>\n'
                  '      <name>%s</name>\n'
                  '      <Icon>\n'
                  '        <href>overlay.png</href>\n'
                  '      </Icon>\n'
                  '      <LatLonBox>\n'
                  '        <north>%f</north>\n'
                  '        <south>%f</south>\n'
                  '        <east>%f</east>\n'
                  '        <west>%f</west>\n'
                  '      </LatLonBox>\n'
                  '    </GroundOverlay>\n'
                  '  </Folder>\n'
                  '</kml>\n'
              ) % (overlay_name, self.north_latitude, self.south_latitude, self.east_longitude, self.west_longitude)

        with codecs.open('overlay.kml', encoding='utf-8', mode='w+') as kmlFile:
            kmlFile.write(kml)

    def create_kmz(self):
        self.create_temp_png()
        self.create_kml()
        with ZipFile(self.kmz_file, 'w') as zipObj:
            # zipObj.writestr(kml_output_filename, kml)  # Add doc.kml entry
            zipObj.write('overlay.kml')
            zipObj.write('overlay.png')

if __name__ == '__main__':
    ql_image_filename = r'D:\test\DJI_20230410091240_0035.tif'
    kml_output_filename = r'D:\test\DJI_20230410091240_0035.kmz'
    tif2kmz = tif2kmz(ql_image_filename, kml_output_filename).create_kmz()

代码解释

tif2kmz

这个类主要用于处理GeoTIFF文件并将其转换为KMZ文件。初始化方法接受两个参数:GeoTIFF文件路径和输出KMZ文件路径。

get_attribute方法

该方法读取GeoTIFF文件并获取其地理位置信息。这些信息将用于生成KML文件,以便在Google Earth中正确显示图像。

linear_stretch方法

该方法对图像数据进行线性拉伸,以增强对比度。线性拉伸是一种图像增强技术,通过将像素值映射到新的范围来提高图像的可见性。

create_temp_png方法

该方法将GeoTIFF文件转换为PNG格式的图片。首先读取GeoTIFF文件中的数据,然后对每个通道(红、绿、蓝)应用线性拉伸,最后将处理后的数据保存为PNG文件。

create_kml方法

该方法生成一个KML文件,该文件包含了PNG图片的地理位置信息。KML文件将描述PNG图片如何覆盖在地图上,以便在Google Earth中正确显示。

create_kmz方法

该方法将生成的KML文件和PNG文件打包成KMZ文件。KMZ文件是KML文件的压缩版本,可以更方便地在Google Earth中使用。

主函数

主函数中,我们实例化tif2kmz类并调用create_kmz方法,将指定的GeoTIFF文件转换为KMZ文件。

总结

通过上述步骤,我们成功地将GeoTIFF文件转换为KMZ文件。这个过程利用了GDAL库读取GeoTIFF数据,Pillow库处理图像数据,以及zipfile库创建KMZ文件。这个转换过程可以帮助我们更方便地在Google Earth中查看和分析地理信息数据。

后续会把tif转为kzm的功能添加到大疆粗校正小工具里。

下一步计划是,去除无人机照片里的黑边。