Gis数据存储
- 零、前言
- 一、基础概念
- 二、矢量数据
- 1、定义
- 2、基础
- 3、WBT/WKB
- 4、坐标系
- 5、Geometry
- 6、要素 / 要素集
- 7、存储格式
- 8、图层
- 三、栅格数据
- 1、定义
- 2、基础
- 3、存储格式
零、前言
1、首先该篇文档主要是针对刚入坑的朋友,如果你对gis的存储结构谙熟于心,建议略过该篇
2、相信刚入坑gis的朋友一定会听到各种各样的数据存储格式,当别人聊起之时,自己却没有涉及,只能暂时记录然后自行百度解决,不仅耗时,书面的解释又晦涩难懂;
介于以上原因,此篇文档横空出世,立志让入坑gis的伙伴能够快速上手gis的数据存储格式,该篇文档会加入很多自身的理解,难免会存在不足,还望各位不要吝惜自己的所见所闻,一起完善这篇文档,毕竟前人种树,后人点火嘛
3、由于想要把本人的所知所想全部表达出来,所以本片文档的文字描述较多,还请耐心看下去,相信对小白还是有一定帮助的
4、本文涉及编程方面的知识,默认语言为java
5、学无止尽,gis的水深不见底,本人也只是一个在岸边停留的人,这篇文档也只是冰山一角
一、基础概念
1、首先得明确,如今(2023)主要的两种gis数据存储分为两大类:“矢量” 和 “栅格”,这两种下又有自己的具体存储形式(特定场景下可以相互转化);对这两种数据的处理是截然不同的,还望不要混淆
2、熟记1,其实久而久之,自然就能区分了,但是如果是刚入坑的对概念还很模糊,还请仔细区分
二、矢量数据
1、定义
矢量数据是在直角坐标中,用x、y坐标表示地图图形或地理实体的位置和形状的数据。矢量数据一般通过记录坐标的方式来尽可能地将地理实体的空间位置表现得准确无误(百度百科)
2、基础
(1)矢量是带方向(主要是顺/逆时针)的,一些图形(主要是环形)方向是有特殊含义的
(2)众所周知,二维图形可分为 点、线、面三个大类
这三大类下又可细分为各自的小类(实际使用时主要是针对这些小类)
点:单点(Point)
线:单线(LineString)、环线(LineString,首尾相连的线)
面:单面(Polygon)、环(Polygon,有内环的面)
(3)当然,在实际使用中,肯定会遇到由多个图形组成一个整体的图形
例如:一个群岛,他有很多互相隔离小岛,此时只靠一个面是无法精准描述这个群岛的样子了
这个时候,就引入了多面(MultiPolygon)的概念,同理还有多点(MultiPoint)、多线(MultiLineString)
这些带 "多" 的的图形,实际就是一个由任意数量,有相同类型的单个图形组成的一个"大"图形
(4)诶,这个时候就有吴彦祖要问了,如果一个图形他又有点,又有面该怎么办呢
当然这个问题,我们的前人也想到了,于是就有了几何集合(GeometryCollection)的概念
几何集合他其实就是一个任意数量,含有不同类型的单个图形组成的一个"大"图形
(5)到这,一个图形具体的表示方法就能归纳出来了(这里也只是列举了一些常用的,还有很多其他的就需要自行百度了)
点:单点(Point)、多点(MultiPoint)
线:单线(LineString)、环线(LineString,首尾相连的线)、多线(MultiLineString)
面:单面(Polygon)、环(Polygon,有内环的面)、多面(MultiPolygon)
混合图形:几何集合(GeometryCollection)
3、WBT/WKB
想要表示一个图形,我们就得有一套规范,这套规范就是 WKT(Well-Known Text) 和 WKB(Well-Known Binary),他们的关系:WKT就是文本样子的WKB,WKB就是二进制的WKT
这里主要介绍WKT,毕竟正常人也看不懂WKB,反正有办法可以互转(wkb/wkt互转),不必为难自己;说白了,WKT是给人看的,WKB是给计算机看的,在代码表现形式上两者都是字符串类型
哦,忘了,WKT说人话(我的理解)就是 一种可以用人类可读的文本来表示空间图形的一套规范,熟练之后其实很简单
言归正传,接下来将阐述如何使用WKT表达图形
(1)还有一个概念:
在二维空间内,要想表达一个点,实际就是描述一组横纵坐标(x和y),在地理描述上也只不过是换成了经纬度(longitude 和 latitude)
一条线是由无数的点组成,在这里也不列外,要想表达一条线,实际就是列举出他所包含的点
当然,在计算机中,我们是无法做到列出所有的点,因此,在表达线时,需要尽量少的列举出能够尽可能完全表达其样子的点,如拐点
在计算机中,是不可能完全表达出一条平滑的曲线,因为每两连续的点处的斜率都不同,因为我们也只是尽量列举出有代表性的点,然后交由具体的算法去表达
在了解怎么表达线后,在表达面时,实际上就是描述一条首尾相连的线,然后知道告诉大家他的类型为面即可
(2)要想表达一个图形,首先得先表明其图形类型,就像java要用一个变量,就得先声明其数据类型一样;具体的图形对应的类型,前面也给出了一些(不区分大小写),可做参考
(3)在确定其类型后,接着就是描述图形的样子,就是图形其包含的点,具体只能看下面几个例子了;要想将WKT可视化,可以使用这个网址:WKT可视化
单点:POINT(1 6)
多点:MULTIPOINT(2 2, 5 9)、MULTIPOINT((2 2), (5 9)) 这两个是一样的效果,计算机是会自动识别的,一组点用空格(" ")来分隔x和y,两组点之间用 逗号(",")进行分隔不用的点,以下同理
单线:LINESTRING(1 1, 3 6, 7 0, 5 9, 0 1)
环线:LINESTRING(0 0, 0 10, 10 10, 10 0, 0 0)
多线:MULTILINESTRING((1 1, 4 0, 4 9, 8 3), (13 17, 10 19, 18 14, 12 17, 10 10), (0 0, 0 -10, -10 -10, -10 0, 0 0))
单面:POLYGON((2 4, 0 5, 9 3, 8 3, 8 7, 2 4)) POLYGON((0 0, 0 10, 10 10, 10 0, 0 0)) 表达面时,一定要首尾相连;即使是单面,也必须得把表达的面用括号("()")包裹起来,因为涉及到环的表达
环: POLYGON((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 4 2, 4 4, 2 4, 2 2)) 外环逆,内环顺,矢量的方向性在这就能体现,但这只是一个约定俗称的规范,只是为了增加人类可读性
POLYGON((0 0,0 10,10 10,10 0,0 0), (2 2,2 6,6 6,6 2,2 2), (3 3,3 8,8 8,8 3,3 3)) 实际上计算机是按照 “单数为实,双数为空”(也就是某块空间在整体出现的次数) 的逻辑来判断是否图形是否被挖空
多面:MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0)), ((3 3, 3 5, 5 5, 5 3, 3 3))) 和多点多线类似,只是要注意一个面需要用双层括号("(())")包裹
4、坐标系
坐标系主要有以下两种
(1)地理坐标系:在真实地球上,使用实际的经纬线来描述实际位置(点)的坐标系。
由于地球实际为不规则图形,因此根据不同地方对地球形状的不同解释,就出现了不同的地理坐标系,常见的有4490、4326
4326:EPSG4326是基于WGS84椭球的经纬度坐标系(大地坐标系,BL),除中国外,国际上普遍使用4326来描述位置
4490:EPSG4490是基于CGCS2000椭球的经纬度坐标系(地理坐标系),中国国内常常使用4490来描述位置
实际上,这两者相差的误差不会很大,在使用时基本可以认为是一致的
(2)投影坐标系:将真实地球投影到二维空间(地图)上时,此时就需要用到投影坐标系来描述位置(使用x和y,但依旧是使用经纬度进行表达)
根据投影方法不同,也出现了不同的投影坐标系,常见的有 4490(等距投影,使用经纬度直投)、3857(墨卡托投影,也叫等角投影)
3857:使用底面圆直径刚好等于地球赤道处圆直径的圆柱体将地球包裹,以地心为原点,连接地心和地表点形成一条射线,射线与圆柱体侧面相交的点是即为该点在平面的投影,最后将圆柱体侧面展开就是墨卡托投影(航海地图)
4490:即在平面内,单个方向上(x或y),每一度的距离都是相等的投影;投影时就是将其在地理坐标系下的经纬度,直接放在平面坐标系下即可
5、Geometry
在了解了坐标系后,我们就会知道,同一个图形,在不同的投影坐标系下,它所表达的地理图形(在真实地球上的样子)是可能会有差距的
因此,我们在描述一个地理上的物体时,如一片湖泊,不止要描述其形状,还得为其指定一个坐标系,这样才能精准的表达其在地理上的图形
因为,我们将这两者合并起来,于是就出现了Geometry(一个类,在jts包下)的概念,其中的geometry表示图形,srid属性表示坐标系
当然,除了图形和坐标系,一个图形还有很多其他有用的可用信息,如面的面积、线的长度等,但这些都能通过其图形和坐标系结合算出来
6、要素 / 要素集
到这,我们会发现Geometry所能表达的所有信息都是其图形本身的,在实际使用时我们通常会结合其他信息一同使用
例如我们要描述杭州市,我们可以用Geometry来描述其地理轮廓,但当我们还需要存储其如人口数量、近几年的GDP时,Geometry就无能为力了
这个时候,我们就引入了要素的概念,在java里就是一个带有Geometry属性的自定义类的一个实例对象;在数据库,如postgres,其表现就是一个带有空间字段的表中的一条记录;它可以自定义一些其它你所需要存储的信息
多个要素组合起来就形成了一个集合(collection,数组、列表、SimpleFeatureCollection等),通常称这个集合为要素集
7、存储格式
当我们已经有了一个要素集后,就可以使用以下的方式存储起来,方便今后使用
(1).gpkg: geopackage文件,文件型数据库(sqlite),可以使用 DB Brower For SQLIite来进行查看(文件见附件1),其查询和mysql相同,
(2)postgres: 数据库,类似mysql,两者的基本语法无区别,但是在一些细节上有区别,例如mysql的上引号(" ` “),在postgres中需要使用双引号(” " ")来表示
可以存储gis信息以及使用gis相关函数
一些常见的空间函数
st_astext(空间字段名):以wkt的形式展示空间信息
st_srid(空间字段名):空间字段对应的坐标系
st_geometryfromtext(空间信息字符串,wkt/wkb/ewkt等):将字符串内容转为Geometry
st_area(空间字段名):空间字段的图形面积
st_xmin(空间字段名) : st_ymin(...) / st_xmax(...) / st_ymax(...):空间字段图形的最小经度 / 最小纬度/ 最大经度 / 最大纬度
更多空间函数可参考:https://desktop.arcgis.com/zh-cn/arcmap/10.7/manage-data/using-sql-with-gdbs/st-numgeometries.htm
(3).geojson: 带有空间信息的json文件,但其最外层只能是大括号(“{}”)包裹,换言之可以理解为一个geojson只能表达一个对象,即一个要素
(4).kml: 带有空间信息的xml文件
(5)shp: ESRI Shapefile(shp),或简称shapefile,由一组文件组成
其中必须含有的文件(一般这几个文件再加上一个.prj文件就够了)
.shp— 图形格式,用于保存元素的几何实体。
.shx— 图形索引格式。几何体位置索引,记录每一个几何体在shp文件之中的位置,能够加快向前或向后搜索一个几何体的效率。
.dbf— 属性数据格式,以dBase IV的数据表格式存储每个几何形状的属性数据。
其他可以包含的文件
.prj— 投帧式,用于保存地理坐标系统与投影信息,是一个存储well-known text投影描述符的文本文件。
.sbnand.sbx— 几何体的空间索引
.fbnand.fbx— 只读的Shapefiles的几何体的空间索引
.ainand.aih— 列表中活动字段的属性索引。
.ixs— 可读写Shapefile文件的地理编码索引
.mxs— 可读写Shapefile文件的地理编码索引(ODB格式)
.atx—.dbf文件的属性索引,其文件名格式为shapefile.columnname.atx(ArcGIS 8及之后的版本)
.shp.xml— 以XML格式保存元数据。
.cpg— 用于描述.dbf文件的代码页,指明其使用的字符编码。
8、图层
首先明确,一个要素集,就是一个图层
因为存储格式的区别,一些存储格式是可以在同一个位置放入多个要素集,也就是常说的多图层存储格式
(1)postgres 一张表只能存入一个要素集,通常一张表中我们只处理一个空间字段,当有多个空间字段时,默认处理第一个空间字段,因此可以认为一张表是单图层存储格式
一个库可以有多张表,所以一个库可以理解为多图层存储,
在实际使用时,我们的操作单元一般为表,所以可以认为postgres是一个单图层存储格式
(2).gpkg 因为其本质是一个数据库,所以它可以存储多张表,实际使用中对其的操作单元一般为整个文件,所以可以认为gpkg是一个多图层存储格式
(3).geojson 一个标准的geojson最外层只能用大括号(“{}”)包裹,也就意味着它只能表达一个要素集,因此,geojson是一个单图层存储格式
geojson还有另外两种衍生文件类型:.geojsons和.geojsonl,同样也只能是单图层存储格式
(4).kml kml文件和geojson一样,也只能是单图层存储格式
(5)shp 一组shp文件只能表示一个图层,因此一组shp文件是单图层存储格式
由于其是由一组文件组成,它就会有一个父目录,而我们也可以操作该目录,工具通常会自动识别里面存储的shp文件组,既然是目录,就表明它是可以存储多组shp文件的,此时,该目录就是多图层存储格式
在实际使用时,我们操作单元一般为shp文件组,而不是shp文件组的目录,所以通常认为shp文件是单图层存储格式
三、栅格数据
1、定义
栅(shān)格数据就是将空间分割成有规律的网格,每一个网格称为一个单元,并在各单元上赋予相应的属性值来表示实体的一种数据形式。每一个单元(像素)的位置由它的行列号定义,所表示的实体位置隐含在栅格行列位置中,数据组织中的每个数据表示地物或现象的非几何属性或指向其属性的指针。一个优秀的压缩数据编码方案是:在最大限度减少计算机运算时间的基点上进行最大幅度的压缩。(百度百科)
2、基础
首先要先理解几个定义
(1)像素:像素就是一个个有明确位置和颜色的小方格,很多像素组合在一起就能形成我们平时所看到的图片
(2)分辨率:可以理解为一单位面积中所包含的像素个数,但通常这一单位就代指整个图片或屏幕,所以分辨率可以描述为 图片长的像素个数 * 图片宽的像素个数
由定义就可知,分辨率越高,图片越清晰,我们常说的马赛克就是一副分辨率极低的图片,低到可能只有几个像素
下面就是一些计算机的分辨率
(3)灰度值:把一种颜色最低的程度与最高的程度分为若干级,称为“灰度等级”,范围一般从0到255,其中每一个值都表示一个精确的颜色深浅程度,这个值就叫“灰度值”
通常灰度值越小,颜色越深,如 红色(0)到 红色(255):就是从深红(当然当灰度值为0时,视觉上就是黑色)到浅红
(4)波段:首先明确,一个波段,就是一个带颜色的灰度值矩阵,矩阵中每个灰度值代表该种颜色在对应像素下的颜色深浅程度,或者其对应的色段映射列表
当一个栅格文件只有一个波段时,那我们就称其为单波段栅格文件
既然有单波段栅格文件,那就一定有多波段栅格文件,顾名思义,即该栅格文件中含有多个颜色波段
如上图所示,一个栅格文件含有三个颜色(红/绿/蓝)的波段,
最左边的是他们对应的灰度值矩阵,
中间的是每个灰度值矩阵带上其对应颜色后的视觉效果,
最右边是将这三个波段叠加在一起后的效果,也是平常看到的栅格文件效果
(5)掩膜(mask):首先,掩膜通常也是一个灰度值矩阵
日常生活中,很少有图像能完整的覆盖整个文件,因此会留有很多的空白地方,而这些空间地方是不需要展示,也就是图片背景
所以我们处理时需要识别出这些空白地方,通常我们会给这些空白地方的像素填充一个指定的灰度值,并记录在指定地方,在图像处理时会对所有灰度值为指定值的像素做特殊处理
在栅格文件中,这个在空白处填充的值叫做空白值(noDataValue),在渲染图像时,会将图像矩阵的每个像素的灰度值与对应的掩膜矩阵灰度值对比,当满足某种关系(异或,与,非等)时,对该像素做处理
如上图,mask就是掩膜矩阵,上图的关系就是:当掩膜矩阵的像素灰度值为0时,不论原图该像素的灰度值是多少,最后灰度值都为0;当为1时,最后结果则为原图在该像素的灰度值
3、存储格式
(1).tif / .tiff:标准的tif文件,文件存储了一个或者多个波段,在win11系统下,可以使用图片查看器直接查看tif文件,视觉效果是所有波段叠加后的图片效果
tif文件中使用noDataValue值来存储tif的空白值
(2)cogtif: 云端tif文件,本质上还是一个tif文件
在开发中,tif文件常常是存储在云端而非本地,当一张tif过大时,会出现下载困难的情况
因此就诞生了cogtif文件,目的是为了更加高效下载、使用存储在云端的tif文件