IT TIP

주어진 그림에서 긴 / 위도를 픽셀 x / y로 변환

itqueen 2020. 11. 21. 08:27
반응형

주어진 그림에서 긴 / 위도를 픽셀 x / y로 변환


모스크바의 도시지도가 있습니다. 일부 예술적 요소로 Google지도 이미지를 수정했지만 GPS 좌표와 픽셀 간의 관계는 동일하게 유지됩니다.

문제점 : 우리가 가지고있는 다양한 데이터 포인트의 GPS 좌표를 이미지의 픽셀 좌표로 어떻게 변환합니까?

이상적으로는 Javascript로 할 수 있지만 PHP는 괜찮습니다.


나는 작은 규모 (예 : 도시 규모)에서 충분히 간단하게 만들 수 있다는 것을 알고 있습니다 (어떤 지리적 좌표에 그림 모서리 중 하나가 있는지 알아 낸 다음 축에있는 사진의 지리적 좌표에서 한 픽셀의 "가격"을 배우는 것이 필요합니다) OX 및 OY는 별도로).

그러나 큰 규모 (국가 규모)에서는 한 픽셀의 "가격"이 일정하지 않고 충분히 다양하며 위에서 설명한 방법을 적용 할 수 없습니다.

국가 규모의 문제를 해결하는 방법은 무엇입니까?


최신 정보:

저는 API Google Maps를 사용하지 않습니다. 객체의 지리적 좌표 (Google지도에서 가져온 것임) 만 있습니다. 내 사이트에는 여전히 간단한 그림이 있습니다 *. 지리 좌표에 해당하는 점을 그려야합니다.


이 모든 것의 핵심은 지도 투영을 이해하는 것 입니다. 다른 사람들이 지적했듯이 왜곡의 원인은 구형 (또는 더 정확하게는 타원체) 지구가 평면에 투영된다는 사실입니다.

목표를 달성하려면 먼저 데이터에 대해 두 가지 사항을 알아야합니다.

  1. 지도가있는 투영입니다. 순전히 Google지도 에서 파생 된 경우 구형 메르카토르 투영을 사용하고있을 가능성이 있습니다.
  2. 위도 / 경도 좌표가 사용하는 지리적 좌표계입니다. 지구상에서 위도 / 경도를 찾는 방법이 다르기 때문에 이것은 다를 수 있습니다. 대부분의 웹 매핑 애플리케이션 및 GPS에 사용되는 가장 일반적인 GCS는 WGS84 입니다.

나는 당신의 데이터가 이러한 좌표계에 있다고 가정합니다.

구형 메르카토르 투영법은 지표면의 좌표 쌍을 미터 단위로 정의합니다. 즉, 모든 위도 / 경도 좌표에 대해 일치하는 미터 / 미터 좌표가 있습니다. 이렇게하면 다음 절차를 사용하여 변환을 수행 할 수 있습니다.

  1. 이미지 모서리의 WGS84 위도 / 경도를 찾습니다.
  2. WGS 위도 / 경도를 구형 메르카토르 투영법으로 변환합니다. 거기에 변환 도구가 있는데, 제가 가장 좋아하는 것은 PROJ4 프로젝트의 일부인 cs2cs 도구를 사용하는 것입니다 .
  3. 단순 선형 변환을 수행하여 이미지의 점과 구형 메르카토르 투영에서 지구상의 점 사이를 변환하고 다시 그 반대로 변환 할 수 있습니다.

WGS84 지점에서 이미지의 픽셀로 이동하기위한 절차는 다음과 같습니다.

  1. 위도 / 경도를 구형 메르카토르로 투영합니다. 이것은 proj4js 라이브러리를 사용하여 수행 할 수 있습니다 .
  2. 위에서 발견 한 선형 관계를 사용하여 구형 메르카토르 좌표를 이미지 픽셀 좌표로 변환합니다.

다음과 같이 proj4js 라이브러리를 사용할 수 있습니다.

// include the library
<script src="lib/proj4js-combined.js"></script>  //adjust the path for your server
                                                 //or else use the compressed version
// creating source and destination Proj4js objects
// once initialized, these may be re-used as often as needed
var source = new Proj4js.Proj('EPSG:4326');    //source coordinates will be in Longitude/Latitude, WGS84
var dest = new Proj4js.Proj('EPSG:3785');     //destination coordinates in meters, global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/


// transforming point coordinates
var p = new Proj4js.Point(-76.0,45.0);   //any object will do as long as it has 'x' and 'y' properties
Proj4js.transform(source, dest, p);      //do the transformation.  x and y are modified in place

//p.x and p.y are now EPSG:3785 in meters

귀하의 언어로 Google Maps API 투영을 구현해야합니다. 이에 대한 C # 소스 코드가 있습니다.

public class GoogleMapsAPIProjection
{
    private readonly double PixelTileSize = 256d;
    private readonly double DegreesToRadiansRatio = 180d / Math.PI;
    private readonly double RadiansToDegreesRatio = Math.PI / 180d;
    private readonly PointF PixelGlobeCenter;
    private readonly double XPixelsToDegreesRatio;
    private readonly double YPixelsToRadiansRatio;

    public GoogleMapsAPIProjection(double zoomLevel)
    {
        var pixelGlobeSize = this.PixelTileSize * Math.Pow(2d, zoomLevel);
        this.XPixelsToDegreesRatio = pixelGlobeSize / 360d;
        this.YPixelsToRadiansRatio = pixelGlobeSize / (2d * Math.PI);
        var halfPixelGlobeSize = Convert.ToSingle(pixelGlobeSize / 2d);
        this.PixelGlobeCenter = new PointF(
            halfPixelGlobeSize, halfPixelGlobeSize);
    }

    public PointF FromCoordinatesToPixel(PointF coordinates)
    {
        var x = Math.Round(this.PixelGlobeCenter.X
            + (coordinates.X * this.XPixelsToDegreesRatio));
        var f = Math.Min(
            Math.Max(
                 Math.Sin(coordinates.Y * RadiansToDegreesRatio),
                -0.9999d),
            0.9999d);
        var y = Math.Round(this.PixelGlobeCenter.Y + .5d * 
            Math.Log((1d + f) / (1d - f)) * -this.YPixelsToRadiansRatio);
        return new PointF(Convert.ToSingle(x), Convert.ToSingle(y));
    }

    public PointF FromPixelToCoordinates(PointF pixel)
    {
        var longitude = (pixel.X - this.PixelGlobeCenter.X) /
            this.XPixelsToDegreesRatio;
        var latitude = (2 * Math.Atan(Math.Exp(
            (pixel.Y - this.PixelGlobeCenter.Y) / -this.YPixelsToRadiansRatio))
            - Math.PI / 2) * DegreesToRadiansRatio;
        return new PointF(
            Convert.ToSingle(latitude),
            Convert.ToSingle(longitude));
    }
}

출처:

http://code.google.com/p/geographical-dot-net/source/browse/trunk/GeographicalDotNet/GeographicalDotNet/Projection/GoogleMapsAPIProjection.cs


위도 / 경도 좌표를 가져와 해당 위치의 이미지에서 픽셀 좌표를 찾고 싶습니까?

기본 GMap2 클래스는 표시된지도의 픽셀과 위도 / 경도 좌표 간의 변환을 제공합니다.

Gmap2.fromLatLngToContainerPixel(latlng)

예를 들면 :

var gmap2 = new GMap2(document.getElementById("map_canvas"));
var geocoder = new GClientGeocoder();

geocoder.getLatLng( "1600 Pennsylvania Avenue NW Washington, D.C. 20500",
    function( latlng ) {
        var pixel_coords = gmap2.fromLatLngToContainerPixel(latlng);

        window.alert( "The White House is at pixel coordinates (" + 
            pixel_coodrs.x + ", " + pixel_coords.y + ") on the " +
            "map image shown on this page." );
    }
);

따라서지도 이미지가 Google지도 디스플레이의 화면 캡처라고 가정하면 위도 / 경도 좌표의 해당 이미지에 올바른 픽셀 좌표가 제공됩니다.

전체 타일 세트의 영역이 표시된 맵의 영역 외부에 있기 때문에 타일 이미지를 가져 와서 직접 연결하는 경우 상황이 더 까다 롭습니다.

이 경우 왼쪽 상단 이미지 타일의 왼쪽 및 상단 값을 fromLatLngToContainerPixel (latlng : GLatLng)에서 제공하는 좌표의 오프셋으로 사용해야합니다. y 좌표. 따라서 왼쪽 상단 이미지가 (-50, -122) (왼쪽, 상단)에 있고 fromLatLngToContainerPixel ()에서 위도 / 경도가 픽셀 좌표 (150, 320)에 있다고 알려 주면 이미지에서 타일에서 좌표의 실제 위치는 (150-(-50), 320-(-122)), 즉 (200, 442)입니다.

유사한 GMap2 좌표 변환 함수가 다음과 같은 경우도 가능합니다.

GMap2.fromLatLngToDivPixel(latlng:GLatLng)

스티치 타일 케이스에 대한 정확한 위도 / 경도를 픽셀 변환으로 제공합니다. 저는 이것을 테스트하지 않았으며 API 문서에서도 100 % 명확하지 않습니다.

자세한 내용은 여기를 참조하십시오. http://code.google.com/apis/maps/documentation/reference.html#GMap2.Methods.Coordinate-Transformations


gheat 에서 사용 된 코드를 볼 수 있으며 js에서 python으로 포팅되었습니다.


당신이 다루고있는 번역 은 우리 세계의 구형 표면이 2 차원 렌더링으로 번역되는 방식 인 Map Projection 과 관련이 있습니다. 2D 표면에 세계를 렌더링하는 여러 방법 (투영)이 있습니다.

지도에서 특정 투영법 만 사용하는 경우 ( 메르카토르 가 널리 사용됨 ) 방정식, 일부 샘플 코드 및 / 또는 일부 라이브러리 (예 : 하나의 메르카토르 솔루션- 위도 / 경도를 X / Y 좌표로 변환)를 찾을 수 있습니다. . 그 그것을하지 않는 경우에, 나는 확신 다른 샘플을 찾을 수 있습니다 - https://stackoverflow.com/search?q=mercator을 . 이미지는 메르카토르 투영을 사용하여 (들)을지도하지 않는 경우, 당신에게 ' 올바른 번역 방정식을 찾기 위해 어떤 투영법을 사용하는지 결정해야합니다.

여러지도 투영을 지원하려는 경우 (다른 투영을 사용하는 여러 다른지도를 지원하려는 경우) 분명히 PROJ.4 와 같은 라이브러리를 사용하고 싶지만 자바 스크립트에서 무엇을 찾을 수 있을지 잘 모르겠습니다. 또는 PHP.


각 픽셀이 동일한 영역에 있다고 가정하는 경우 거리를 경도 / 위도 좌표로 변환하는 방법에 대한 다음 문서가 도움이 될 수 있습니다.

http://www.johndcook.com/blog/2009/04/27/converting-miles-to-degrees-longitude-or-latitude/


위도와 경도를 직각 좌표로 변환하려면 수식이 필요합니다. 선택할 수있는 수는 많으며 각각은 다른 방식으로지도를 왜곡합니다. Wolfram MathWorld에는 좋은 컬렉션이 있습니다.

http://mathworld.wolfram.com/MapProjection.html

"참고 항목"링크를 따르십시오.


고려해야 할 중요한 사항 중 하나는 투영의 "확대 / 축소"수준입니다 (특히 Google지도의 경우).

Google이 설명하는대로 :

확대 / 축소 수준 1에서지도는 4 개의 256x256 픽셀 타일로 구성되어 512x512의 픽셀 공간이됩니다. 확대 / 축소 수준 19에서지도의 각 x 및 y 픽셀은 0에서 256 * 2 ^ 19 사이의 값을 사용하여 참조 할 수 있습니다.

( https://developers.google.com/maps/documentation/javascript/maptypes?hl=ko#MapCoordinates 참조 )

"zoom"값을 고려하려면 아래 의 간단하고 효과적인 deltaLonPerDeltaXdeltaLatPerDeltaY 함수를 권장합니다 . x- 픽셀과 경도는 엄격하게 비례하지만 공식에 초기 위도가 필요한 y- 픽셀 및 위도의 경우에는 해당되지 않습니다.

// Adapted from : http://blog.cppse.nl/x-y-to-lat-lon-for-google-maps


window.geo = {

    glOffset: Math.pow(2,28), //268435456,
    glRadius:  Math.pow(2,28) / Math.PI,
    a: Math.pow(2,28),
    b: 85445659.4471,
    c: 0.017453292519943,
    d: 0.0000006705522537,
    e: Math.E, //2.7182818284590452353602875,
    p: Math.PI / 180,

    lonToX: function(lon) {
        return Math.round(this.glOffset + this.glRadius * lon * this.p);
    },

    XtoLon: function(x) {
        return -180 + this.d * x;
    },

    latToY: function(lat) {
        return Math.round(this.glOffset - this.glRadius *
                          Math.log((1 + Math.sin(lat * this.p)) /
                          (1 - Math.sin(lat * this.p))) / 2);
    },

    YtoLat: function(y) {
        return Math.asin(Math.pow(this.e,(2*this.a/this.b - 2*y/this.b)) /
                                 (Math.pow(this.e, (2*this.a/this.b - 2*y/this.b))+1) -
                                 1/(Math.pow(this.e, (2*this.a/this.b - 2*y/this.b))+1)
                        ) / this.c;
    },

    deltaLonPerDeltaX: function(deltaX, zoom) {
        // 2^(7+zoom) pixels <---> 180 degrees
        return deltaX * 180 / Math.pow(2, 7+zoom);
    },

    deltaLatPerDeltaY: function(deltaY, zoom, startLat) {
        // more complex because of the curvature, we calculte it by difference
        var startY = this.latToY(startLat),
            endY = startY + deltaY * Math.pow(2, 28-7-zoom),
            endLat = this.YtoLat(endY);

        return ( endLat - startLat ); // = deltaLat
    }
}

my approach works without a library and with cropped maps. Means it works with just parts from a Mercator image. Maybe it helps somebody: https://stackoverflow.com/a/10401734/730823


Struggled with this - Have both openstreet map and google street map and wanted to project an external graphic image

var map = new OpenLayers.Map({
            div:"map-id",
            allOverlays: true
    });
    var osm = new OpenLayers.Layer.OSM("OpenStreeMao");
    var gmap = new OpenLayers.Layer.Google("Google Streets", {visibility: false});

    map.addLayers([osm,gmap]);

    var vectorLayer = new OpenLayers.Layer.Vector("IconLayer");


    var lonlatObject = new OpenLayers.LonLat(24.938622,60.170421).transform(
            new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()
    );
    console.log(lonlatObject);

    var point = new OpenLayers.Geometry.Point(lonlatObject.lon, lonlatObject.lat);
    console.log(point);

    var point2 = new OpenLayers.Geometry.Point(lonlatObject.x, lonlatObject.y);
    console.log(point2);

    var feature = new OpenLayers.Feature.Vector(point, null, {
        externalGraphic:  "http://cdn1.iconfinder.com/data/icons/SUPERVISTA/networking/png/72/antenna.png",
        graphicWidth: 72,
        graphicHeight: 72,
        fillOpacity: 1
    });


    vectorLayer.addFeatures(feature);

    map.addLayer(vectorLayer);


    map.setCenter(
            new OpenLayers.LonLat(24.938622,60.170421).transform(
            new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject()
            ),
            12);

     map.addControl(new OpenLayers.Control.LayerSwitcher());

http://jsfiddle.net/alexcpn/N9dLN/8/

참고URL : https://stackoverflow.com/questions/2651099/convert-long-lat-to-pixel-x-y-on-a-given-picture

반응형