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代码。

#!/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命令行程序,作为一个特定功能的小工具分享给大家。

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文件。
pip install gdal numpy Pillow

实现步骤

1. 创建类tif2kmz

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

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文件时使用。

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,对图像数据进行线性拉伸,以增强图像对比度。

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格式的图片。

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文件

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文件。

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方法。

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()

完整代码

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的功能添加到大疆粗校正小工具里。

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