GeoTrellis 进行影像切片

学习GeoTrellis是我最难的一段时间,资料很少,群也很少。靠着自己一点一点摸索,稍稍能做出点结果。分享给大家。

在这里也是很感谢网上的各位大佬,没有他们的帮助,也就没有今天的这篇文章。我也只不过踩在巨人的肩膀上,做了一些简单的整理。

我并没有使用官方的sbt,而是使用了maven进行搭建。需要注意的是,需要IDEA安装Scala并在maven中添加框架支持,将Scala添加其中。

首先利用IDEA构建一个Maven项目。pom.xml 内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>GeoTrellis</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <scala.version>2.11.8</scala.version>
  </properties>

  <pluginRepositories>
    <pluginRepository>
      <id>scala-tools.org</id>
      <name>Scala-Tools Maven2 Repository</name>
      <url>http://scala-tools.org/repo-releases</url>
    </pluginRepository>
  </pluginRepositories>

  <dependencies>
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
      <version>${scala.version}</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.specs</groupId>
      <artifactId>specs</artifactId>
      <version>1.2.5</version>
      <scope>test</scope>
    </dependency>

    <!-- 添加依赖 -->
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-spark_2.11</artifactId>
      <version>2.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-raster_2.11</artifactId>
      <version>2.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-spark-etl_2.11</artifactId>
      <version>2.0.1</version>
    </dependency>
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-cassandra_2.11</artifactId>
      <version>2.0.1</version>
    </dependency>
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-proj4_2.11</artifactId>
      <version>2.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-util_2.11</artifactId>
      <version>2.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.locationtech.geotrellis</groupId>
      <artifactId>geotrellis-macros_2.11</artifactId>
      <version>2.1.0</version>
    </dependency>

    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-actor_2.11</artifactId>
      <version>2.4.17</version>
    </dependency>
    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-http-core_2.11</artifactId>
      <version>10.0.3</version>
    </dependency>
    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-http_2.11</artifactId>
      <version>10.0.3</version>
    </dependency>
    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-http-spray-json_2.11</artifactId>
      <version>10.0.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.spark</groupId>
      <artifactId>spark-core_2.11</artifactId>
      <version>2.3.0</version>
    </dependency>

  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/scala</directory>
        <excludes>
          <exclude>**/*.scala</exclude>
        </excludes>
      </resource>
    </resources>

    <sourceDirectory>src/main/scala</sourceDirectory>
    <plugins>
      <plugin>
        <groupId>org.scala-tools</groupId>
        <artifactId>maven-scala-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <scalaVersion>${scala.version}</scalaVersion>
          <args>
            <arg>-target:jvm-1.8</arg>
          </args>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <configuration>
          <downloadSources>true</downloadSources>
          <buildcommands>
            <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
          </buildcommands>
          <additionalProjectnatures>
            <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
          </additionalProjectnatures>
          <classpathContainers>
            <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
            <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
          </classpathContainers>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <reporting>
    <plugins>
      <plugin>
        <groupId>org.scala-tools</groupId>
        <artifactId>maven-scala-plugin</artifactId>
        <configuration>
          <scalaVersion>${scala.version}</scalaVersion>
        </configuration>
      </plugin>
    </plugins>
  </reporting>
</project>

因为在本地测试,因此不用搭建Spark集群也可以,但是需要搭建一个HDFS集群,用来存放数据

在scala文件夹下创建application.conf

创建该配置文件,是为了方便配置管理,各位亲也可以不创建,直接卸载类的变量中。

内容如下:

server {
    port = 8080
    file.path = "I:/0practiceArry/GeoTrellis/out/beijing"
    interface = "0.0.0.0"
}

spark {
    master = "local[*]",
    appName = "GeoTrellis WMTS"
}

geoTrellis {
    hadoop.path = "hdfs://HBase105:9000/GeoTrellis/Beijing.tif"
    outFile.path = "I:/0practiceArry/GeoTrellis/out/beijing"
    instance.fileName = "landsat"
    instance.pngFileName = "pngContainer"
    isPNG = true
    zoom = 10
    tileSize = 256
}
  • server中配置的是akka服务端口和ip,以及切片文件放置的位置
  • spark 中配置的spark的master和应用名称
  • geoTrellis 配置的是:
    • 输入文件路径 —— hadoop.path
    • 输出文件路径 —— outFile.path
    • 生成切片文件夹名称 —— instance.fileName
    • 生成切片png文件夹名称 —— instance.pngFileName
    • 是否生成png瓦片 —— isPNG
    • 设置最大切片等级 —— zoom
    • 设置瓦片大小 —— tileSize
  • 在这里需要注意的是,
    • Beijing.tif 与 Beijing.tiff 没有区别,都可以识别
    • 影像500M的时候,如果内存没有64以上,请不要把tileSize 设置为128 (我试过,64G内存都撑不住)

编写切片代码

本人Scala并不算熟悉,因此有很多地方都有所借鉴。一些个人理解,还请各位大佬指导。

导入包

这个部分我拿出来说,是因为很多地方都需要(隐式?)导入,所以直接先贴出来

import java.io.File

import com.typesafe.config.{Config, ConfigFactory}
import geotrellis.proj4._
import geotrellis.raster._
import geotrellis.raster.render._
import geotrellis.raster.resample._
import geotrellis.spark._
import geotrellis.spark.io.file._
import geotrellis.spark.io.hadoop._
import geotrellis.spark.io._
import geotrellis.spark.io.index._
import geotrellis.spark.pyramid._
import geotrellis.spark.tiling._
import org.apache.spark.rdd.RDD
import org.apache.spark._

import geotrellis.vector._
import org.apache.spark.rdd._

获取配置文件中的值

val config: Config = ConfigFactory.load()
//  输入文件路径
private val hadoopInPath: String = config.getString("geoTrellis.hadoop.path")
//  输出文件路径
private val outFilePath: String = config.getString("geoTrellis.outFile.path")

//  spark Master
private val master: String = config.getString("spark.master")
//  spark 应用名称
private val appName: String = config.getString("spark.appName")

//  切片等级
private val setZoom: Int = config.getInt("geoTrellis.zoom")
private val tileSize: Int = config.getInt("geoTrellis.tileSize")

//  是否生成PNG
private val isPNG: Boolean = config.getBoolean("geoTrellis.isPNG")
//  实例名称
private val instanceFileName: String = config.getString("geoTrellis.instance.fileName")
//  图片实例名称
private val InstancePNGFileName: String = config.getString("geoTrellis.instance.pngFileName")

创建Spark配置

  private val sparkConf: SparkConf = new SparkConf()
    .setAppName(appName)
    .setMaster(master)
    .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    .set("spark.kryo.registrator", "geotrellis.spark.io.kryo.KryoRegistrator")

  val sparkContext = new SparkContext(sparkConf)

main函数

  def main(args: Array[String]): Unit = {
    try {
      run(sparkContext)
    } finally {
      sparkContext.stop()
    }
  }

主函数 run

  def run(implicit sparkContext: SparkContext): Unit = {
    //    构建GeoRDD
    //    ProjectedExtent类型值必须赋予,否则创建元数据信息的时候会报找不到
    val geoRDD: RDD[(ProjectedExtent, Tile)] = sparkContext.hadoopGeoTiffRDD(hadoopInPath)

    //    创建元数据信息
    val (_, rasterMetaData) = TileLayerMetadata.fromRDD(geoRDD, FloatingLayoutScheme(512))

    //    创建切片RDD
    val tiled: RDD[(SpatialKey, Tile)] = geoRDD.
      tileToLayout(rasterMetaData.cellType, rasterMetaData.layout, Bilinear)
	// 请特别注意,此处咨询过 GeoTrellis 的作者,请不要随意的使用repartition!!
	// repartition 会将所有的数据进行重新分区,增加计算量!
    //  .repartition(100)

    //    设置投影和瓦片大小
    val layoutScheme: ZoomedLayoutScheme = ZoomedLayoutScheme(WebMercator, tileSize = tileSize)

    val (maxZoom, reprojected) = TileLayerRDD(tiled, rasterMetaData)
      .reproject(WebMercator, layoutScheme, Bilinear)

    //    创建输出存储区
    val attributeStore = FileAttributeStore(outFilePath)
    val writer = FileLayerWriter(attributeStore)

    val colorRender = ColorRamps.LightToDarkSunset

    Pyramid.upLevels(reprojected, layoutScheme, setZoom, Bilinear) { (rdd, z) =>
      val landsatId = LayerId(instanceFileName, z)

      //      写出图层
      writer.write(landsatId, rdd, ZCurveKeyIndexMethod)

      //      如果需要生成PNG则生成PNG
      if (isPNG) {
        renderPNG(sparkContext, z, colorRender)
      }
    }
  }

Pyramid.upLevels 函数是从最大切片等级开始进行运算的(个人理解哈,因为Spark运行时,是从最大等级任务开始执行的)

渲染PNG

def renderPNG(implicit sparkContext: SparkContext, zoom: Int, colorRender: Any): Unit = {
    val path = outFilePath + "/" + instanceFileName
    val file = new File(path)

    //    如果不存在,则直接停止运行
    if (!file.exists()) {
      sparkContext.stop()
    }

    //    创建png结果文件夹
    val pngOutFileName = outFilePath + "/" + InstancePNGFileName
    createFolder(pngOutFileName)

    //    获取文件名
    val files = file.listFiles()

    files.foreach(item => {
      val zoomLevel = item.getName

      //    创建级别文件夹
      val zoomLevelFileName = pngOutFileName + "/" + zoomLevel
      createFolder(zoomLevelFileName)

      //    读取图层
      val reader = FileLayerReader(outFilePath)
      val layerId = LayerId(instanceFileName, zoomLevel.toInt)

      /*
      * 应该导入 import geotrellis.spark.io._
      * */
      val layers: RDD[(SpatialKey, Tile)] with Metadata[TileLayerMetadata[SpatialKey]] =
        reader.read[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId)

//      GeoTrellis 与Google 的 ZXY相同
      layers.foreach(layer => {
        val key = layer._1
        val tile = layer._2

        //        定义x
        val outPathPNGYFileName = zoomLevelFileName + '/' + key.col
        createFolder(outPathPNGYFileName)

        //        定义y
        val pngFileName = outPathPNGYFileName + "/" + key.row + ".png"

        colorRender match {
          case ramp: ColorRamp =>
            tile.renderPng(ramp).write(pngFileName)

          case ramp: ColorMap =>
            tile.renderPng(ramp).write(pngFileName)
        }
      })
    })
  }
  
    /*
  * 创建文件夹
  * */
  def createFolder(folderName: String): File = {
    val file = new File(folderName)

    //    如果没有图片输出文件夹,则创建
    if (!file.exists()) {
      file.mkdirs()
    }

    file
  }
  

创建PNG的时候,需要手动创建文件夹,GeoTrellis 的切片规则与Google相同, ZXY

通过

reader.read[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId) 

获取指定级别下的切片数据,他是个RDD算子,因此此过程依然需要Spark环境。

在定义颜色的时候,需要注意的是,ColorMap 是值对值的一一对应关系映射,也就是说,一个值是一个颜色,而不是一个范围(唯一值渲染),而ColorRamp是一个色彩范围(色带)

结果

如果生成PNG的话,则目录结构如下:

在pngContainer中是切片图片,可以直接利用web 容器进行发布,采用 XYZ的方式进行加载。

创建PNG的时候,需要手动创建文件夹,GeoTrellis 的切片规则与Google相同, ZXY

通过

reader.read[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](layerId) 

获取指定级别下的切片数据,他是个RDD算子,因此此过程依然需要Spark环境。

在定义颜色的时候,需要注意的是,ColorMap 是值对值的一一对应关系映射,也就是说,一个值是一个颜色,而不是一个范围(唯一值渲染),而ColorRamp是一个色彩范围(色带)

结果

如果生成PNG的话,则目录结构如下:

在这里插入图片描述

在pngContainer中是切片图片,可以直接利用web 容器进行发布,采用 XYZ的方式进行加载。

在landsat中的文件,需要利用akka或者是Spring boot 进行后台处理后,才能渲染给前端。

  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
ArcGIS影像切片发布服务是指将高分辨率的影像数据分割成小块切片,并通过互联网或网络服务进行发布,以供用户进行在线地图浏览和数据分析。 首先,ArcGIS平台具备强大的影像处理能力,可以处理各种类型的影像数据,包括航空摄影、卫星遥感等。通过ArcGIS Desktop中的影像切片工具,可以将原始影像数据根据需要进行分块切片,每个切片形成一个独立的文件。将这些切片文件进行组织和管理,可以方便地对影像数据进行管理和使用。 接下来,通过ArcGIS Server提供的影像切片发布服务,可以将这些切片文件进行托管,形成一个可以通过网络访问的影像切片地图服务。用户可以通过ArcGIS Online等平台或自己搭建的地图服务进行访问,浏览和查询影像切片地图。 ArcGIS影像切片发布服务的优点有: 1. 高效性:通过将大型影像数据分割成小块切片,可以提高影像数据的传输和加载效率,减少用户在浏览和使用影像数据时的等待时间。 2. 可视化:通过影像切片地图服务,用户可以以切片形式加载和浏览整个影像数据集,同时可以进行放大、缩小、平移等操作,以观察地表特征和进行数据分析。 3. 可伸缩性:ArcGIS Server提供了可伸缩的影像切片发布服务,可以根据用户需求,进行服务的动态扩展,以支持大量用户的访问和数据查询。 4. 数据共享:通过影像切片发布服务,用户可以将自己的影像数据共享给其他用户,并设置不同的权限和访问控制,实现数据共享和集成。 5. 多维数据支持:除了二维影像数据,ArcGIS影像切片发布服务还支持灰度图像、多波段图像等多维度数据的发布和显示。 总之,ArcGIS影像切片发布服务是一种方便、高效和可扩展的影像数据发布方式,能够满足用户对在线地图浏览和数据分析的需求,为GIS应用提供了更加强大和丰富的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值