使用OpenLayers 5在地图上添加旋转的卫星图像 [英] Add a rotated satellite image on the map using OpenLayers 5

查看:5
本文介绍了使用OpenLayers 5在地图上添加旋转的卫星图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用OpenLayers 5在地图上添加卫星图像。

问题是我无法做到这一点,因为我刚刚找到了一个选项,可以在地图上添加经过图像范围(xmin、ymin、xmax、ymax)而不是边界框的图像。图像应适合边界框内。因此,图像被扭曲。

图像在JPG文件中(属性Feature.Properties.ICON)。示例:http://exampleserver.com/220/063/353LGN00/353LGN00_thumb_large.jpg

我想要的结果是这样的:

我得到的结果是:

我在地图上添加此图像的代码如下:

import ImageLayer from 'ol/layer/Image'
import Static from 'ol/source/ImageStatic'

...

this.olmap = new Map({
    target: 'map',
    layers: [
      baseLayerGroup, rasterLayerGroup, vectorLayer
    ],
    view: new View({
        projection: 'EPSG:4326',
        center: [ -45.8392, -3.65286 ],
        zoom: 8
    })
})

...

this.rasterLayerGroup.getLayers().push(
    new ImageLayer({
        source: new Static({
            url: feature.properties.icon,
            projection: 'EPSG:4326',
            imageExtent: [
              feature.properties.bl_longitude, feature.properties.bl_latitude,
              feature.properties.tr_longitude, feature.properties.tr_latitude
            ]  
        })
    })
)

有人知道如何传递图像边界框而不仅仅是图像范围吗?

提前谢谢您。

编辑1:Mike的解决方案

通过Mike的解决方案,我能够修复一些图像(在赤道线附近)存在的错误。出于这个原因,他的回答解决了我的问题,并将图像插入了我在创建问题时所期望的更好的位置。

然而,这个解决方案对我来说很有效,因为图像靠近赤道线。电线杆旁的图像保持扭曲(编辑2)。

我在下面发一张图片说明最终结果:

编辑2:新问题?

我正在测试一些图像,我发现了一个新的错误。现在我发现图像应该放在边界框中。如果图像不适合BBox,它将保持扭曲状态,例如我在下面发送的插图。

图像应适合BBox内,如下图所示[ps 1]

我认为这可能是重新投影的问题,但我不知道,因为视图投影和图像投影都是EPSG:4326。

我尝试按照有关栅格重投影的说明进行操作[1]。然而,在OpenLayers网站上,我无法复制它,因为正如我所说的,这两个投影(视图和图像)是相同的(或者它们应该是相同的)。

我在下面发送了包含与上面图像相关的信息的GeoJSON。图片可以在属性图标(http://www.dpi.inpe.br/newcatalog/tmp/MOD13Q1/2018/MOD13Q1.A2018017.h13v14.jpg)中找到。BBox坐标可以在"geometry.coels"中找到,也可以在"Properties.bl_Latitude"、"Properties.bl_LONGUDE"、"Properties.br_Latitude"等文件中找到。 "bl"表示"左下","br"表示"右下","tl"表示"左上","tr"表示"右上"。"属性"中的这些坐标与"geometry.coels"中的坐标相同。

{
  "geometry": {
    "coordinates": [
      [
        [
          -77.7862,
          -50
        ],
        [
          -100,
          -60
        ],
        [
          -80,
          -60
        ],
        [
          -62.229,
          -50
        ],
        [
          -77.7862,
          -50
        ]
      ]
    ],
    "type": "Polygon"
  },
  "properties": {
    "alternate": "http://www.dpi.inpe.br/opensearch/v2/granule.json?uid=MOD13Q1.A2018017.h13v14",
    "auxpath": null,
    "bitslips": null,
    "bl_latitude": -60,
    "bl_longitude": -100,
    "br_latitude": -60,
    "br_longitude": -80,
    "centerlatitude": -55,
    "centerlongitude": -80.0038,
    "centertime": null,
    "cloud": 0,
    "cloudcovermethod": "M",
    "dataset": "MOD13Q1",
    "date": "2018-01-17T00:00:00",
    "enclosure": [
      {
        "band": "evi",
        "radiometric_processing": "SR",
        "type": "MOSAIC",
        "url": "http://www.dpi.inpe.br/newcatalog/tmp/MOD13Q1/2018/MOD13Q1.A2018017.h13v14.006.2018033223827.hdf"
      },
      {
        "band": "ndvi",
        "radiometric_processing": "SR",
        "type": "MOSAIC",
        "url": "http://www.dpi.inpe.br/newcatalog/tmp/MOD13Q1/2018/MOD13Q1.A2018017.h13v14.006.2018033223827.hdf"
      },
      ...
    ],
    "icon": "http://www.dpi.inpe.br/newcatalog/tmp/MOD13Q1/2018/MOD13Q1.A2018017.h13v14.jpg",
    "id": "http://www.dpi.inpe.br/opensearch/v2/granule.json?uid=MOD13Q1.A2018017.h13v14",
    "orbit": 0,
    "path": 14,
    "provider": "OP_CBERS1",
    "row": 13,
    "satellite": "T1",
    "sensor": "MODIS",
    "title": "MOD13Q1.A2018017.h13v14",
    "tl_latitude": -50,
    "tl_longitude": -77.7862,
    "tr_latitude": -50,
    "tr_longitude": -62.229,
    "type": "IMAGES",
    "updated": "2018-03-01T18:51:56",
    "via": "http://www.dpi.inpe.br/opensearch/v2/metadata/MOD13Q1.A2018017.h13v14"
  },
  "type": "Feature"
}

有人会有新点子吗?

[ps 1]:将图像放入BBox的原始代码是一个传单代码[2]。我把它发送到下面:

var map = L.map('map').setView([-15.22, -53.23], 5)

...

var anchor = [
    [feature.properties.tl_latitude, feature.properties.tl_longitude],
    [feature.properties.tr_latitude, feature.properties.tr_longitude],
    [feature.properties.br_latitude, feature.properties.br_longitude],
    [feature.properties.bl_latitude, feature.properties.bl_longitude]
]

layer._quicklook = L.imageTransform(feature.properties.icon, anchor).addTo(map)

[1.]https://openlayers.org/en/latest/doc/tutorials/raster-reprojection.html

[2.]https://github.com/ScanEx/Leaflet.imageTransform

推荐答案

如果坐标是照片的坐标,并且包含旋转照片的jpg是epsg:4326(即与子午线和平行线对齐),则您需要包含照片所有角的边框

import {boundingExtent} from 'ol/extent';

....

this.rasterLayerGroup.getLayers().push(
    new ImageLayer({
        source: new Static({
            url: feature.properties.icon,
            projection: 'EPSG:4326',
            imageExtent: boundingExtent([
              [feature.properties.bl_longitude, feature.properties.bl_latitude],
              [feature.properties.br_longitude, feature.properties.br_latitude],
              [feature.properties.tl_longitude, feature.properties.tl_latitude],
              [feature.properties.tr_longitude, feature.properties.tr_latitude]
            ])  
        })
    })
)
然而,您的顶部屏幕截图使jpg本身旋转。如果需要,投影不是EPSG:4326,并且您需要定义一个自定义投影来处理旋转。

我已经设法获得了接近的效果,但简单地拉伸图像以适应多边形并不能给出LEAFLE方法所做的精确的侧面对齐

数据-lang="js"数据-隐藏="真"数据-控制台="真"数据-巴贝尔="假">
var properties = {
    "bl_latitude": -60,
    "bl_longitude": -100,
    "br_latitude": -60,
    "br_longitude": -80,
    "centerlatitude": -55,
    "centerlongitude": -80.0038,
    "icon": "https://www.mikenunn.net/demo/MOD13Q1.A2018017.h13v14.jpg",
    "tl_latitude": -50,
    "tl_longitude": -77.7862,
    "tr_latitude": -50,
    "tr_longitude": -62.229,
};

function overlaySource ( properties ) {

    var projection = ol.proj.get('EPSG:3857');  // leaflet projection

    var extentSize = [0, 0, 4096, 4096];  // arbitary extent for the projection transforms
    var size0 = extentSize[2];
    var size1 = extentSize[3];

    var url = properties.icon;

    var bl = ol.proj.transform([properties.bl_longitude, properties.bl_latitude], 'EPSG:4326', projection);
    var tl = ol.proj.transform([properties.tl_longitude, properties.tl_latitude], 'EPSG:4326', projection);
    var br = ol.proj.transform([properties.br_longitude, properties.br_latitude], 'EPSG:4326', projection);
    var tr = ol.proj.transform([properties.tr_longitude, properties.tr_latitude], 'EPSG:4326', projection);

    function normalTransform(coordinates, output, dimensions) {
        var dims = dimensions || 2;
        for (var i=0; i<coordinates.length; i+=dims) {

            var left = bl[0] + (tl[0]-bl[0]) * coordinates[i+1]/size1;
            var right = br[0] + (tr[0]-br[0]) * coordinates[i+1]/size1;

            var top = tl[1] + (tr[1]-tl[1]) * coordinates[i]/size0;
            var bottom = bl[1] + (br[1]-bl[1]) * coordinates[i]/size0;

            var newCoordinates0 = left + (right-left) * coordinates[i]/size0;
            var newCoordinates1 = bottom + (top-bottom) * coordinates[i+1]/size1;

            c = ol.proj.transform([newCoordinates0, newCoordinates1], projection, 'EPSG:3857');

            //console.log(coordinates[i] + ' ' + coordinates[i+1] + ' ' + c[0] + ' ' + c[1]);

            coordinates[i] = c[0];
            coordinates[i+1] = c[1];

        }
        return coordinates;
    }

    function rotateTransform(coordinates, output, dimensions) {
        var dims = dimensions || 2;
        for (var i=0; i<coordinates.length; i+=dims) {

            c = ol.proj.transform([coordinates[i], coordinates[i+1]], 'EPSG:3857', projection);

            var left = bl[0] + (tl[0]-bl[0]) * (c[1]-bl[1]) /(tl[1]-bl[1]);
            var right = br[0] + (tr[0]-br[0]) * (c[1]-br[1]) /(tr[1]-br[1]);

            var top = tl[1] + (tr[1]-tl[1]) * (c[0]-tl[0])/(tr[0]-tl[0]);
            var bottom = bl[1] + (br[1]-bl[1]) * (c[0]-bl[0])/(br[0]-bl[0]);

            var newCoordinates0 = (c[0]-left)*size0/(right-left);
            var newCoordinates1 = (c[1]-bottom)*size1/(top-bottom);

            //console.log(coordinates[i] + ' ' + coordinates[i+1] + ' ' + newCoordinates0 + ' ' + newCoordinates1);

            coordinates[i] = newCoordinates0;
            coordinates[i+1] = newCoordinates1;

        }
        return coordinates;
    }

    var rotatedProjection = new ol.proj.Projection({
        code: 'EPSG:' + url + 'rotated',
        units: 'm',
        extent: extentSize
    });
    ol.proj.addProjection(rotatedProjection);

    ol.proj.addCoordinateTransforms('EPSG:3857', rotatedProjection,
        function(coordinate) {
            return rotateTransform(coordinate);
        },
        function(coordinate) {
            return normalTransform(coordinate);
        }
    );

    ol.proj.addCoordinateTransforms('EPSG:4326', rotatedProjection,
        function(coordinate) {
            return rotateTransform(ol.proj.transform(coordinate, "EPSG:4326", "EPSG:3857"));
        },
        function(coordinate) {
            return ol.proj.transform(normalTransform(coordinate), "EPSG:3857", "EPSG:4326");
        }
    );

    return new ol.source.ImageStatic({
        projection: rotatedProjection,
        imageExtent: extentSize,
        url: url
    });

}

var tileLayer = new ol.layer.Tile({
    source: new ol.source.XYZ({
        attributions: [
            'Powered by Esri',
            'Source: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community'
        ],
        //attributionsCollapsible: false,
        url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
        maxZoom: 23
    })
});

var imageLayer = new ol.layer.Image({
    source:  overlaySource( properties ),
    opacity: 0.7
})

var map = new ol.Map({
    layers: [tileLayer, imageLayer],
    target: 'map',
    logo: false,
    view: new ol.View()
});

var imageProj = imageLayer.getSource().getProjection();
map.getView().fit(ol.proj.transformExtent(imageProj.getExtent(), imageProj, map.getView().getProjection()), {constrainResolution: false});
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
<div id="map" class="map"></div>

这是我的KML方法,但这只是一个简单的矩形旋转指定角度,而不是将它扭曲成只有两条边平行的四边形。

数据-lang="js"数据-隐藏="真"数据-控制台="真"数据-巴贝尔="假">
function kmlOverlaySource ( kmlExtent, // KMLs specify the extent the unrotated image would occupy
                            url,
                            rotation,
                            imageSize,
) {

    // calculate latitude of true scale of equidistant cylindrical projection based on pixels per degree on each axis

    proj4.defs('EPSG:' + url, '+proj=eqc +lat_ts=' +
                              (Math.acos((ol.extent.getHeight(kmlExtent)/imageSize[1])
                                        /(ol.extent.getWidth(kmlExtent)/imageSize[0]))*180/Math.PI) +
                              ' +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');

    if (ol.proj.proj4 && ol.proj.proj4.register) { ol.proj.proj4.register(proj4); } // if OL5 register proj4

    // convert the extents to source projection coordinates

    var projection = ol.proj.get('EPSG:' + url);
    var projExtent = ol.proj.transformExtent(kmlExtent, 'EPSG:4326', projection);

    var angle = -rotation * Math.PI/180;

    function rotateTransform(coordinates, output, dimensions) {
        var dims = dimensions || 2;
        for (var i=0; i<coordinates.length; i+=dims) {
            var point = new ol.geom.Point([coordinates[i],coordinates[i+1]]);
            point.rotate(angle, ol.extent.getCenter(projExtent));
            var newCoordinates = point.getCoordinates();
            coordinates[i] = newCoordinates[0];
            coordinates[i+1] = newCoordinates[1];
        }
        return coordinates;
    }

    function normalTransform(coordinates, output, dimensions) {
        var dims = dimensions || 2;
        for (var i=0; i<coordinates.length; i+=dims) {
            var point = new ol.geom.Point([coordinates[i],coordinates[i+1]]);
            point.rotate(-angle, ol.extent.getCenter(projExtent));
            var newCoordinates = point.getCoordinates();
            coordinates[i] = newCoordinates[0];
            coordinates[i+1] = newCoordinates[1];
        }
        return coordinates;
    }

    var rotatedProjection = new ol.proj.Projection({
        code: 'EPSG:' + url + 'rotated',
        units: 'm',
        extent: projExtent
    });
    ol.proj.addProjection(rotatedProjection);

    ol.proj.addCoordinateTransforms('EPSG:4326', rotatedProjection,
        function(coordinate) {
            return rotateTransform(ol.proj.transform(coordinate, 'EPSG:4326', projection));
        },
        function(coordinate) {
            return ol.proj.transform(normalTransform(coordinate), projection, 'EPSG:4326');
        }
    );

    ol.proj.addCoordinateTransforms('EPSG:3857', rotatedProjection,
        function(coordinate) {
            return rotateTransform(ol.proj.transform(coordinate, 'EPSG:3857', projection));
        },
        function(coordinate) {
            return ol.proj.transform(normalTransform(coordinate), projection, 'EPSG:3857');
        }
    );

    return new ol.source.ImageStatic({
        projection: rotatedProjection,
        url: url,
        imageExtent: projExtent
    });

}

var tileLayer = new ol.layer.Tile({
    source: new ol.source.XYZ({
        attributions: [
            'Powered by Esri',
            'Source: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community'
        ],
        //attributionsCollapsible: false,
        url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
        maxZoom: 23
    })
});

// these would normally be parsed from a KML file
var kmlExtent = [8.433995415151397, 46.65804355828784, 9.144871415151389, 46.77980155828784];
var url = 'https://raw.githubusercontent.com/ReneNyffenegger/about-GoogleEarth/master/kml/the_png_says.png'
var rotation = 30;
var imageSize = [];

var img = document.createElement('img');
img.onload = imageLoaded;
img.src = url;

function imageLoaded() {

    imageSize[0] = img.width;
    imageSize[1] = img.height;

    var imageLayer = new ol.layer.Image({
        source: kmlOverlaySource(kmlExtent, url, rotation, imageSize),
    });

    var map = new ol.Map({
        layers: [tileLayer, imageLayer],
        target: 'map',
        logo: false,
        view: new ol.View()
    });

    var imageProj = imageLayer.getSource().getProjection();
    map.getView().fit(ol.proj.transformExtent(imageProj.getExtent(), imageProj, map.getView().getProjection()), {constrainResolution: false});

}
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
<div id="map" class="map"></div>

这篇关于使用OpenLayers 5在地图上添加旋转的卫星图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆