美文网首页geotoolsgeotoolsgeotools
geotools学习(五)影像

geotools学习(五)影像

作者: MrSwilder | 来源:发表于2019-10-28 16:25 被阅读0次

    影像应用

    前面的示例中,我们研究了读取和显示shapefile。对于ImageLab.java,我们将通过显示一个三波段的全球卫星图像,并将其与shapefile中的国家边界叠加,从而将栅格数据添加到这个组合中。
    1.请确保您的pom.xml包含以下内容。
    在前面的示例中,我们已经遇到了这些依赖项中的大多数,我们添加的新模块是gt-geotiff,它允许我们从一个GeoTIFF文件中读取栅格地图数据;gt-image,它允许我们读取一个图像+世界格式文件集(如jpg + jpw)。

    <dependencies>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-shapefile</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-swing</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-epsg-hsql</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-geotiff</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-image</artifactId>
                <version>${geotools.version}</version>
            </dependency>
            <dependency>
                <groupId>org.geotools</groupId>
                <artifactId>gt-wms</artifactId>
                <version>${geotools.version}</version>
            </dependency>
          </dependencies>
      <repositories>
          <repository>
              <id>maven2-repository.dev.java.net</id>
              <name>Java.net repository</name>
              <url>http://download.java.net/maven/2</url>
          </repository>
          <repository>
              <id>osgeo</id>
              <name>Open Source Geospatial Foundation Repository</name>
              <url>http://download.osgeo.org/webdav/geotools/</url>
          </repository>
          <repository>
            <snapshots>
              <enabled>true</enabled>
            </snapshots>
            <id>boundless</id>
            <name>Boundless Maven Repository</name>
            <url>http://repo.boundlessgeo.com/main</url>
          </repository>
      </repositories>
    

    2.请创建包 org.geotools.tutorial.raster和类ImageLab和复制粘贴在以下代码:

    package org.geotools.tutorial.raster;
    
    import java.awt.Color;
    import java.awt.event.ActionEvent;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JOptionPane;
    import org.geotools.coverage.GridSampleDimension;
    import org.geotools.coverage.grid.GridCoverage2D;
    import org.geotools.coverage.grid.io.AbstractGridFormat;
    import org.geotools.coverage.grid.io.GridCoverage2DReader;
    import org.geotools.coverage.grid.io.GridFormatFinder;
    import org.geotools.data.FileDataStore;
    import org.geotools.data.FileDataStoreFinder;
    import org.geotools.data.Parameter;
    import org.geotools.data.simple.SimpleFeatureSource;
    import org.geotools.factory.CommonFactoryFinder;
    import org.geotools.gce.geotiff.GeoTiffFormat;
    import org.geotools.map.FeatureLayer;
    import org.geotools.map.GridReaderLayer;
    import org.geotools.map.Layer;
    import org.geotools.map.MapContent;
    import org.geotools.map.StyleLayer;
    import org.geotools.styling.ChannelSelection;
    import org.geotools.styling.ContrastEnhancement;
    import org.geotools.styling.RasterSymbolizer;
    import org.geotools.styling.SLD;
    import org.geotools.styling.SelectedChannelType;
    import org.geotools.styling.Style;
    import org.geotools.styling.StyleFactory;
    import org.geotools.swing.JMapFrame;
    import org.geotools.swing.action.SafeAction;
    import org.geotools.swing.data.JParameterListWizard;
    import org.geotools.swing.wizard.JWizard;
    import org.geotools.util.KVP;
    import org.geotools.util.factory.Hints;
    import org.opengis.filter.FilterFactory2;
    import org.opengis.style.ContrastMethod;
    
    public class ImageLab {
    
        private StyleFactory sf = CommonFactoryFinder.getStyleFactory();
        private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
    
        private JMapFrame frame;
        private GridCoverage2DReader reader;
    
        public static void main(String[] args) throws Exception {
            ImageLab me = new ImageLab();
            me.getLayersAndDisplay();
        }
    
    参数

    直到现在,数据存储向导是如何创建的还是一个谜。向导是根据连接时所需的参数描述创建的。
    我们现在将使用这些相同的工厂来提示用户:
    1.我们将使用JParameterListWizard来提示光栅文件和shapefile将显示在其上:

       /**
         * Prompts the user for a GeoTIFF file and a Shapefile and passes them to the displayLayers
         * method
         */
        private void getLayersAndDisplay() throws Exception {
            List<Parameter<?>> list = new ArrayList<>();
            list.add(
                    new Parameter<>(
                            "image",
                            File.class,
                            "Image",
                            "GeoTiff or World+Image to display as basemap",
                            new KVP(Parameter.EXT, "tif", Parameter.EXT, "jpg")));
            list.add(
                    new Parameter<>(
                            "shape",
                            File.class,
                            "Shapefile",
                            "Shapefile contents to display",
                            new KVP(Parameter.EXT, "shp")));
    
            JParameterListWizard wizard =
                    new JParameterListWizard("Image Lab", "Fill in the following layers", list);
            int finish = wizard.showModalDialog();
    
            if (finish != JWizard.FINISH) {
                System.exit(0);
            }
            File imageFile = (File) wizard.getConnectionParameters().get("image");
            File shapeFile = (File) wizard.getConnectionParameters().get("shape");
            displayLayers(imageFile, shapeFile);
        }
    

    为每个输入文件使用参数对象。传递给参数构造函数的参数是:

    key:参数的标识符
    type:参数引用的对象的类
    title:向导将用于标记文本字段的标题
    description:向导将在文本字段下面显示的简短描述
    metadata:包含参数的附加数据的映射——在我们的例子中是一个或多个文件扩展名
    
    显示地图

    为了在屏幕上显示地图,我们创建了一个MapContent,将图像和shapefile添加到其中,并将其传递给一个JMapFrame。
    1.而不是使用静态JMapFrame。与前面的示例一样,我们创建了一个映射框架,并通过添加一个菜单来选择图像显示模式对其进行自定义。

     /**
         * Displays a GeoTIFF file overlaid with a Shapefile
         *
         * @param rasterFile the GeoTIFF file
         * @param shpFile the Shapefile
         */
        private void displayLayers(File rasterFile, File shpFile) throws Exception {
            AbstractGridFormat format = GridFormatFinder.findFormat(rasterFile);
            // this is a bit hacky but does make more geotiffs work
            Hints hints = new Hints();
            if (format instanceof GeoTiffFormat) {
                hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
            }
            reader = format.getReader(rasterFile, hints);
    
            // Initially display the raster in greyscale using the
            // data from the first image band
            Style rasterStyle = createGreyscaleStyle(1);
    
            // Connect to the shapefile
            FileDataStore dataStore = FileDataStoreFinder.getDataStore(shpFile);
            SimpleFeatureSource shapefileSource = dataStore.getFeatureSource();
    
            // Create a basic style with yellow lines and no fill
            Style shpStyle = SLD.createPolygonStyle(Color.YELLOW, null, 0.0f);
    
            // Set up a MapContent with the two layers
            final MapContent map = new MapContent();
            map.setTitle("ImageLab");
    
            Layer rasterLayer = new GridReaderLayer(reader, rasterStyle);
            map.addLayer(rasterLayer);
    
            Layer shpLayer = new FeatureLayer(shapefileSource, shpStyle);
            map.addLayer(shpLayer);
    
            // Create a JMapFrame with a menu to choose the display style for the
            frame = new JMapFrame(map);
            frame.setSize(800, 600);
            frame.enableStatusBar(true);
            // frame.enableTool(JMapFrame.Tool.ZOOM, JMapFrame.Tool.PAN, JMapFrame.Tool.RESET);
            frame.enableToolBar(true);
    
            JMenuBar menuBar = new JMenuBar();
            frame.setJMenuBar(menuBar);
            JMenu menu = new JMenu("Raster");
            menuBar.add(menu);
    
            menu.add(
                    new SafeAction("Grayscale display") {
                        public void action(ActionEvent e) throws Throwable {
                            Style style = createGreyscaleStyle();
                            if (style != null) {
                                ((StyleLayer) map.layers().get(0)).setStyle(style);
                                frame.repaint();
                            }
                        }
                    });
    
            menu.add(
                    new SafeAction("RGB display") {
                        public void action(ActionEvent e) throws Throwable {
                            Style style = createRGBStyle();
                            if (style != null) {
                                ((StyleLayer) map.layers().get(0)).setStyle(style);
                                frame.repaint();
                            }
                        }
                    });
            // Finally display the map frame.
            // When it is closed the app will exit.
            frame.setVisible(true);
        }
    

    2.请注意,我们正在为每个图层创建一个样式:
    1).用于初始图像显示的灰度样式,使用我们将在下面讨论的方法创建
    2).使用SLD实用程序类的shapefile的简单大纲样式
    3.创建灰度样式提示用户显示图像带;然后生成相应的样式。

      /**
         * Create a Style to display a selected band of the GeoTIFF image as a greyscale layer
         *
         * @return a new Style instance to render the image in greyscale
         */
        private Style createGreyscaleStyle() {
            GridCoverage2D cov = null;
            try {
                cov = reader.read(null);
            } catch (IOException giveUp) {
                throw new RuntimeException(giveUp);
            }
            int numBands = cov.getNumSampleDimensions();
            Integer[] bandNumbers = new Integer[numBands];
            for (int i = 0; i < numBands; i++) {
                bandNumbers[i] = i + 1;
            }
            Object selection =
                    JOptionPane.showInputDialog(
                            frame,
                            "Band to use for greyscale display",
                            "Select an image band",
                            JOptionPane.QUESTION_MESSAGE,
                            null,
                            bandNumbers,
                            1);
            if (selection != null) {
                int band = ((Number) selection).intValue();
                return createGreyscaleStyle(band);
            }
            return null;
        }
    
        /**
         * Create a Style to display the specified band of the GeoTIFF image as a greyscale layer.
         *
         * <p>This method is a helper for createGreyScale() and is also called directly by the
         * displayLayers() method when the application first starts.
         *
         * @param band the image band to use for the greyscale display
         * @return a new Style instance to render the image in greyscale
         */
        private Style createGreyscaleStyle(int band) {
            ContrastEnhancement ce = sf.contrastEnhancement(ff.literal(1.0), ContrastMethod.NORMALIZE);
            SelectedChannelType sct = sf.createSelectedChannelType(String.valueOf(band), ce);
    
            RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
            ChannelSelection sel = sf.channelSelection(sct);
            sym.setChannelSelection(sel);
    
            return SLD.wrapSymbolizers(sym);
        }
    

    4.要显示颜色,我们需要使用稍微复杂一点的样式,它指定网格覆盖中的哪些波段映射到屏幕上的红色、绿色和蓝色。
    该方法检查图像,看看其频带(称为样本尺寸)是否有标签表明使用哪个。如果不是,我们只使用前三个波段,并希望最好的!

      * This method examines the names of the sample dimensions in the provided coverage looking for
         * "red...", "green..." and "blue..." (case insensitive match). If these names are not found it
         * uses bands 1, 2, and 3 for the red, green and blue channels. It then sets up a raster
         * symbolizer and returns this wrapped in a Style.
         *
         * @return a new Style object containing a raster symbolizer set up for RGB image
         */
        private Style createRGBStyle() {
            GridCoverage2D cov = null;
            try {
                cov = reader.read(null);
            } catch (IOException giveUp) {
                throw new RuntimeException(giveUp);
            }
            // We need at least three bands to create an RGB style
            int numBands = cov.getNumSampleDimensions();
            if (numBands < 3) {
                return null;
            }
            // Get the names of the bands
            String[] sampleDimensionNames = new String[numBands];
            for (int i = 0; i < numBands; i++) {
                GridSampleDimension dim = cov.getSampleDimension(i);
                sampleDimensionNames[i] = dim.getDescription().toString();
            }
            final int RED = 0, GREEN = 1, BLUE = 2;
            int[] channelNum = {-1, -1, -1};
            // We examine the band names looking for "red...", "green...", "blue...".
            // Note that the channel numbers we record are indexed from 1, not 0.
            for (int i = 0; i < numBands; i++) {
                String name = sampleDimensionNames[i].toLowerCase();
                if (name != null) {
                    if (name.matches("red.*")) {
                        channelNum[RED] = i + 1;
                    } else if (name.matches("green.*")) {
                        channelNum[GREEN] = i + 1;
                    } else if (name.matches("blue.*")) {
                        channelNum[BLUE] = i + 1;
                    }
                }
            }
            // If we didn't find named bands "red...", "green...", "blue..."
            // we fall back to using the first three bands in order
            if (channelNum[RED] < 0 || channelNum[GREEN] < 0 || channelNum[BLUE] < 0) {
                channelNum[RED] = 1;
                channelNum[GREEN] = 2;
                channelNum[BLUE] = 3;
            }
            // Now we create a RasterSymbolizer using the selected channels
            SelectedChannelType[] sct = new SelectedChannelType[cov.getNumSampleDimensions()];
            ContrastEnhancement ce = sf.contrastEnhancement(ff.literal(1.0), ContrastMethod.NORMALIZE);
            for (int i = 0; i < 3; i++) {
                sct[i] = sf.createSelectedChannelType(String.valueOf(channelNum[i]), ce);
            }
            RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
            ChannelSelection sel = sf.channelSelection(sct[RED], sct[GREEN], sct[BLUE]);
            sym.setChannelSelection(sel);
    
            return SLD.wrapSymbolizers(sym);
        }
    }
    

    5.请注意,上面的技术(检查颜色带)是特定于RGB图像的。而这对于一个简单的彩色图像来说是很容易的;在卫星图像中,没有一条波段与人眼所见完全一致,这就比较困难了。

    运行程序

    如果你需要一些样本数据显示,你可以下载uDig sample data set,其中包括:
    clouds.jpg
    countries.shp
    1.当你运行程序时,你将首先看到向导对话框提示你的图像和shapefile。

    image.png
    2.初始地图显示将图像显示为灰度、单波段视图。
    image.png
    3.实验显示不同的灰度波段和交换到RGB显示。

    其他尝试

    1.修改文件提示向导或菜单,以允许将附加的shapefile覆盖到映像上。
    2.使用frame.enableLayerTable(true)将映射层表添加到JMapFrame中,以便可以切换层的可见性。
    3.高级:实验风格的光栅显示:例如,对比度增强选项;显示基于范围的图像波段值
    4.高级:您还可以使用地理工具处理来自远程Web地图服务的光栅信息。

    /*
     *    GeoTools - The Open Source Java GIS Toolkit
     *    http://geotools.org
     *
     *    (C) 2019, Open Source Geospatial Foundation (OSGeo)
     *
     *    This library is free software; you can redistribute it and/or
     *    modify it under the terms of the GNU Lesser General Public
     *    License as published by the Free Software Foundation;
     *    version 2.1 of the License.
     *
     *    This library is distributed in the hope that it will be useful,
     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     *    Lesser General Public License for more details.
     *
     */
    
    package org.geotools.tutorial.wms;
    
    import java.net.URL;
    import java.util.List;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import org.geotools.map.MapContent;
    import org.geotools.ows.wms.Layer;
    import org.geotools.ows.wms.WebMapServer;
    import org.geotools.ows.wms.map.WMSLayer;
    import org.geotools.swing.JMapFrame;
    import org.geotools.swing.wms.WMSChooser;
    import org.geotools.swing.wms.WMSLayerChooser;
    
    /**
     * This is a Web Map Server "quickstart" doing the minimum required to display something on screen.
     */
    public class WMSLab extends JFrame {
        /**
         * Prompts the user for a wms service, connects, and asks for a layer and then and displays its
         * contents on the screen in a map frame.
         */
        public static void main(String[] args) throws Exception {
            // display a data store file chooser dialog for shapefiles
            URL capabilitiesURL = WMSChooser.showChooseWMS();
            if (capabilitiesURL == null) {
                System.exit(0); // canceled
            }
            WebMapServer wms = new WebMapServer(capabilitiesURL);
    
            List<Layer> wmsLayers = WMSLayerChooser.showSelectLayer(wms);
            if (wmsLayers == null) {
                JOptionPane.showMessageDialog(null, "Could not connect - check url");
                System.exit(0);
            }
            MapContent mapcontent = new MapContent();
            mapcontent.setTitle(wms.getCapabilities().getService().getTitle());
    
            for (Layer wmsLayer : wmsLayers) {
                WMSLayer displayLayer = new WMSLayer(wms, wmsLayer);
                mapcontent.addLayer(displayLayer);
            }
            // Now display the map
            JMapFrame.showMap(mapcontent);
        }
    }
    

    栅格数据

    网格覆盖
    栅格覆盖的概念提供了对栅格数据的支持。作为程序员,我们习惯于使用位图形式的光栅数据,如JPEG、GIF和PNG文件。
    在地理空间方面,有一个覆盖的概念。覆盖是空间定位特征的集合。通俗地说,我们将覆盖等同于地图(在地理意义上而不是编程意义上)。
    网格覆盖是一种特殊的覆盖情况,其中的特征是矩形,形成一个网格,填充覆盖区域,在我们的Java代码中,我们可以使用位图图形作为GridCoverage的基础数据结构,并使用其他元素记录特定坐标参考系统中的空间界限
    网格覆盖文件格式有很多种。最常见的是:
    World plus image:
    一种普通的图像格式,如jpeg或png,有一个侧车文件描述它的位置,还有一个prj侧车文件定义地图投影,就像shapefile使用的一样。
    请注意,虽然jpeg格式是常见的,因为下载规模小;运行时的性能非常糟糕,因为需要将整个映像读入内存。TIFF等格式没有这种限制,
    GeoTiff
    在图像元数据字段中存储地理空间信息的普通tiff图像。这通常是快速性能的安全保证;特别是如果它已经准备了一个内部覆盖(可以使用时,缩小)或内部平铺(允许快速锅时,放大。
    当您的计算机具有比cpu更快的磁盘时,性能最好。
    JPEG2000
    jpeg的续集,使用小波压缩处理大量图像。文件格式还支持可用于存储地理空间信息的元数据字段。
    当您的cpu速度比磁盘访问速度快时,这种格式的性能最好。
    如果您在JRE中安装了imageio-ext项目,还可以支持ECW和MRSID等其他格式。

    Web Map Server

    图像的另一个来源是Web地图服务器(WMS)。Web地图服务器规范是由开放地理空间联盟定义的——这是一个鼓励在这类事情上进行协作的行业组织。
    在一个基本的层面上,我们可以获取信息从一个WMS使用GetMap操作:

    http://localhost:8080/geoserver/wms?bbox=-130,24,-66,50&styles=population&Format=image/png&request=GetMap&layers=topp:states&width=550&height=250&srs=EPSG:4326
    

    技巧是知道在发出这些请求时要为“层”和“样式”填充哪些参数。
    WMS服务提供了一个getcapability文档,该文档描述了哪些层可用,以及哪些其他操作(如GetMap)可用于在这些层上工作。
    GeoTools有一个很好的实现来帮助我们——它可以解析层列表的功能文档,支持的图像格式等等。

    URL url = new URL("http://atlas.gc.ca/cgi-bin/atlaswms_en?VERSION=1.1.1&Request=GetCapabilities&Service=WMS");
    
    WebMapServer wms = new WebMapServer(url);
    WMSCapabilities capabilities = wms.getCapabilities();
    
    // gets all the layers in a flat list, in the order they appear in
    // the capabilities document (so the rootLayer is at index 0)
    List layers = capabilities.getLayerList();
    

    WebMapServer类还知道如何为几个不同版本的WMS标准设置GetMap请求。

    GetMapRequest request = wms.createGetMapRequest();
    request.setFormat("image/png");
    request.setDimensions("583", "420"); //sets the dimensions to be returned from the server
    request.setTransparent(true);
    request.setSRS("EPSG:4326");
    request.setBBox("-131.13151509433965,46.60532747661736,-117.61620566037737,56.34191403281659");
    
    GetMapResponse response = (GetMapResponse) wms.issueRequest(request);
    BufferedImage image = ImageIO.read(response.getInputStream());
    

    相关文章

      网友评论

        本文标题:geotools学习(五)影像

        本文链接:https://www.haomeiwen.com/subject/dpybvctx.html