谷歌地图 - 如何从地址获取建筑物的多边形坐标?

发布于 2024-10-25 18:36:42 字数 208 浏览 2 评论 0原文

如何实现以下内容:

  1. 用户定义地址
  2. 用户定义颜色
  3. 服务在谷歌地图上搜索相应的建筑物
  4. 颜色填充地图上找到的建筑物

服务用我知道如何的

: 1.查找地址的纬度/经度

2 .绘制多边形

因此,为了完成任务,我需要从地址获取建筑物的多边形坐标。怎样做?

How to implement the following:

  1. User defines an address
  2. User defines a color
  3. Service searches for a corresponding building on the google map
  4. Service fills the found building on the map with the color

I know how to:

1.find lat/long of the address

2.draw the polygon

So, to do the task I need to get polygon coordinates of building from address. How to?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

许你一世情深 2024-11-01 18:36:42

(1) 获取图片tile

original

(2) 基于分段建筑物关于像素颜色(此处为 0xF2EEE6)。

parsed

(3) 图像清理(例如 先腐蚀后膨胀) + 获取多边形角点像素坐标的算法。

(4) 墨卡托投影以获取像素的纬度/经度

(1) Acquire image tile

original

(2) Segment buildings based on pixel color (here, 0xF2EEE6).

parsed

(3) Image cleanup (e.g. erosion then dilation) + algorithm to acquire pixel coordinates of polygon corners.

(4) Mercator projection to acquire lat/long of pixel

荒岛晴空 2024-11-01 18:36:42

您可以使用 Google Geocoding API 将地址转换为地理坐标。

https://maps.googleapis.com/maps/api/geocode/json?address=SOME_ADDRESS&key=YOUR_API_KEY

然后,您可以使用 Python 和样式化的静态地图来获取某个位置处建筑物的多边形(以像素坐标表示):

import numpy as np
from requests.utils import quote
from skimage.measure import find_contours, points_in_poly, approximate_polygon
from skimage import io
from skimage import color
from threading import Thread

center_latitude = None ##put latitude here 
center_longitude = None ##put longitude here 
mapZoom = str(20)
midX = 300
midY = 300
# Styled google maps url showing only the buildings
safeURL_Style = quote('feature:landscape.man_made|element:geometry.stroke|visibility:on|color:0xffffff|weight:1')
urlBuildings = "http://maps.googleapis.com/maps/api/staticmap?center=" + str_Center + "&zoom=" + mapZoom + "&format=png32&sensor=false&size=" + str_Size + "&maptype=roadmap&style=visibility:off&style=" + safeURL_Style

mainBuilding = None
imgBuildings = io.imread(urlBuildings)
gray_imgBuildings = color.rgb2gray(imgBuildings)
# will create inverted binary image
binary_imageBuildings = np.where(gray_imgBuildings > np.mean(gray_imgBuildings), 0.0, 1.0)
contoursBuildings = find_contours(binary_imageBuildings, 0.1)

for n, contourBuilding in enumerate(contoursBuildings):
    if (contourBuilding[0, 1] == contourBuilding[-1, 1]) and (contourBuilding[0, 0] == contourBuilding[-1, 0]):
        # check if it is inside any other polygon, so this will remove any additional elements
        isInside = False
        skipPoly = False
        for othersPolygon in contoursBuildings:
            isInside = points_in_poly(contourBuilding, othersPolygon)
            if all(isInside):
                skipPoly = True
                break

        if skipPoly == False:
            center_inside = points_in_poly(np.array([[midX, midY]]), contourBuilding)
            if center_inside:
        # approximate will generalize the polygon
                mainBuilding = approximate_polygon(contourBuilding, tolerance=2)

print(mainBuilding)

现在,您可以使用少量 JavaScript 和 Google 地图将像素坐标转换为纬度和经度应用程序编程接口:

function point2LatLng(point, map) {
        var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
        var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
        var scale = Math.pow(2, map.getZoom());
        var worldPoint = new google.maps.Point(point.x / scale + bottomLeft.x, point.y / scale + topRight.y);
        return map.getProjection().fromPointToLatLng(worldPoint);
}

var convertedPointsMain = [];

for (var i = 0; i < pxlMainPolygons[p].length; i++) {
    var conv_point = {
        x: Math.round(pxlMainPolygons[p][i][1]),
        y: Math.round(pxlMainPolygons[p][i][0])
    }; 
    convertedPointsMain[i] = point2LatLng(conv_point, map);
}

console.log(convertedPointsMain);

You can convert the address to geographic coordinates by the use of the Google Geocoding API.

https://maps.googleapis.com/maps/api/geocode/json?address=SOME_ADDRESS&key=YOUR_API_KEY

Then, you can use Python and a styled static map to obtain the polygon of the building (in pixel coordinates) at some location:

import numpy as np
from requests.utils import quote
from skimage.measure import find_contours, points_in_poly, approximate_polygon
from skimage import io
from skimage import color
from threading import Thread

center_latitude = None ##put latitude here 
center_longitude = None ##put longitude here 
mapZoom = str(20)
midX = 300
midY = 300
# Styled google maps url showing only the buildings
safeURL_Style = quote('feature:landscape.man_made|element:geometry.stroke|visibility:on|color:0xffffff|weight:1')
urlBuildings = "http://maps.googleapis.com/maps/api/staticmap?center=" + str_Center + "&zoom=" + mapZoom + "&format=png32&sensor=false&size=" + str_Size + "&maptype=roadmap&style=visibility:off&style=" + safeURL_Style

mainBuilding = None
imgBuildings = io.imread(urlBuildings)
gray_imgBuildings = color.rgb2gray(imgBuildings)
# will create inverted binary image
binary_imageBuildings = np.where(gray_imgBuildings > np.mean(gray_imgBuildings), 0.0, 1.0)
contoursBuildings = find_contours(binary_imageBuildings, 0.1)

for n, contourBuilding in enumerate(contoursBuildings):
    if (contourBuilding[0, 1] == contourBuilding[-1, 1]) and (contourBuilding[0, 0] == contourBuilding[-1, 0]):
        # check if it is inside any other polygon, so this will remove any additional elements
        isInside = False
        skipPoly = False
        for othersPolygon in contoursBuildings:
            isInside = points_in_poly(contourBuilding, othersPolygon)
            if all(isInside):
                skipPoly = True
                break

        if skipPoly == False:
            center_inside = points_in_poly(np.array([[midX, midY]]), contourBuilding)
            if center_inside:
        # approximate will generalize the polygon
                mainBuilding = approximate_polygon(contourBuilding, tolerance=2)

print(mainBuilding)

Now, you can convert the pixel coordinates to latitude and longitude by the use of little JavaScript, and the Google Maps API:

function point2LatLng(point, map) {
        var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
        var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
        var scale = Math.pow(2, map.getZoom());
        var worldPoint = new google.maps.Point(point.x / scale + bottomLeft.x, point.y / scale + topRight.y);
        return map.getProjection().fromPointToLatLng(worldPoint);
}

var convertedPointsMain = [];

for (var i = 0; i < pxlMainPolygons[p].length; i++) {
    var conv_point = {
        x: Math.round(pxlMainPolygons[p][i][1]),
        y: Math.round(pxlMainPolygons[p][i][0])
    }; 
    convertedPointsMain[i] = point2LatLng(conv_point, map);
}

console.log(convertedPointsMain);
脱离于你 2024-11-01 18:36:42

我可以谦虚地建议您使用 OpenStreetMaps 来代替吗?
这要容易得多,因为这样您就可以使用 OverPass API
但是,多边形可能与谷歌地图或州调查不匹配。
如果您使用谷歌地图,后者也适用。

// https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
private static string GetOqlBuildingQuery(int distance, decimal latitude, decimal longitude)
{
    System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo()
    {
        NumberGroupSeparator = "",
        NumberDecimalSeparator = ".",
        CurrencyGroupSeparator = "",
        CurrencyDecimalSeparator = ".",
        CurrencySymbol = ""
    };

    // [out: json];
    // way(around:25, 47.360867, 8.534703)["building"];
    // out ids geom meta;

    string oqlQuery = @"[out:json];
way(around:" + distance.ToString(nfi) + ", "
+ latitude.ToString(nfi) + ", " + longitude.ToString(nfi)
+ @")[""building""];
out ids geom;"; // ohne meta - ist minimal

    return oqlQuery;
}




public static System.Collections.Generic.List<Wgs84Point> GetWgs84PolygonPoints(int distance, decimal latitude, decimal longitude)
{
    string[] overpass_services = new string[] {
        "http://overpass.osm.ch/api/interpreter",
        "http://overpass.openstreetmap.fr/api/interpreter",
        "http://overpass-api.de/api/interpreter",
        "http://overpass.osm.rambler.ru/cgi/interpreter",
        // "https://overpass.osm.vi-di.fr/api/interpreter", // offline...
    };

    // string url = "http://overpass.osm.ch/api/interpreter";
    // string url = "http://overpass-api.de/api/interpreter";
    string url = overpass_services[s_rnd.Next(0, overpass_services.Length)];


    System.Collections.Specialized.NameValueCollection reqparm = new System.Collections.Specialized.NameValueCollection();
    reqparm.Add("data", GetOqlBuildingQuery(distance, latitude, longitude));

    string resp = PostRequest(url, reqparm);
    // System.IO.File.WriteAllText(@"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", resp, System.Text.Encoding.UTF8);
    // System.Console.WriteLine(resp);
    // string resp = System.IO.File.ReadAllText(@"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", System.Text.Encoding.UTF8);

    System.Collections.Generic.List<Wgs84Point> ls = null;

    Overpass.Building.BuildingInfo ro = Overpass.Building.BuildingInfo.FromJson(resp);

    if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null)
    {
        ls = new System.Collections.Generic.List<Wgs84Point>();

        for (int i = 0; i < ro.Elements[0].Geometry.Count; ++i)
        {
            ls.Add(new Wgs84Point(ro.Elements[0].Geometry[i].Latitude, ro.Elements[0].Geometry[i].Longitude, i));
        } // Next i 

    } // End if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null) 


    return ls;
} // End Function GetWgs84Points 

Might I humbly suggest you use OpenStreetMaps for this instead ?
It's a lot easier, because then you can use the OverPass API.
However, polygons might not match with google-maps or with state survey.
The latter also holds true if you would use google-maps.

// https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
private static string GetOqlBuildingQuery(int distance, decimal latitude, decimal longitude)
{
    System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo()
    {
        NumberGroupSeparator = "",
        NumberDecimalSeparator = ".",
        CurrencyGroupSeparator = "",
        CurrencyDecimalSeparator = ".",
        CurrencySymbol = ""
    };

    // [out: json];
    // way(around:25, 47.360867, 8.534703)["building"];
    // out ids geom meta;

    string oqlQuery = @"[out:json];
way(around:" + distance.ToString(nfi) + ", "
+ latitude.ToString(nfi) + ", " + longitude.ToString(nfi)
+ @")[""building""];
out ids geom;"; // ohne meta - ist minimal

    return oqlQuery;
}




public static System.Collections.Generic.List<Wgs84Point> GetWgs84PolygonPoints(int distance, decimal latitude, decimal longitude)
{
    string[] overpass_services = new string[] {
        "http://overpass.osm.ch/api/interpreter",
        "http://overpass.openstreetmap.fr/api/interpreter",
        "http://overpass-api.de/api/interpreter",
        "http://overpass.osm.rambler.ru/cgi/interpreter",
        // "https://overpass.osm.vi-di.fr/api/interpreter", // offline...
    };

    // string url = "http://overpass.osm.ch/api/interpreter";
    // string url = "http://overpass-api.de/api/interpreter";
    string url = overpass_services[s_rnd.Next(0, overpass_services.Length)];


    System.Collections.Specialized.NameValueCollection reqparm = new System.Collections.Specialized.NameValueCollection();
    reqparm.Add("data", GetOqlBuildingQuery(distance, latitude, longitude));

    string resp = PostRequest(url, reqparm);
    // System.IO.File.WriteAllText(@"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", resp, System.Text.Encoding.UTF8);
    // System.Console.WriteLine(resp);
    // string resp = System.IO.File.ReadAllText(@"D:\username\Documents\visual studio 2017\Projects\TestPlotly\TestSpatial\testResponse.json", System.Text.Encoding.UTF8);

    System.Collections.Generic.List<Wgs84Point> ls = null;

    Overpass.Building.BuildingInfo ro = Overpass.Building.BuildingInfo.FromJson(resp);

    if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null)
    {
        ls = new System.Collections.Generic.List<Wgs84Point>();

        for (int i = 0; i < ro.Elements[0].Geometry.Count; ++i)
        {
            ls.Add(new Wgs84Point(ro.Elements[0].Geometry[i].Latitude, ro.Elements[0].Geometry[i].Longitude, i));
        } // Next i 

    } // End if (ro != null && ro.Elements != null && ro.Elements.Count > 0 && ro.Elements[0].Geometry != null) 


    return ls;
} // End Function GetWgs84Points 
通知家属抬走 2024-11-01 18:36:42

我已经为此工作了几个小时,最接近的是找到一个请求 uri,该 uri 返回其中包含多边形的结果。我相信它通过 editids 参数指定建筑物(边界)。我们只需要一种从建筑物(边界)获取当前 editid 的方法。

我拥有的 URI 是:

https://www.google.com/mapmaker?hl=en&gw=40&output=jsonp&ll=38.934911%2C-92.329359&spn=0.016288%2C0.056477&z=14&mpnum=0&vpid=1354239392511&editids=nAlkfrzSpBMuVg-hSJ&xauth=YOUR_XAUTH_HERE&geowiki_client=mapmaker&hl=en

结果的一部分包含所需的内容:

"polygon":[{"gnew":{"loop":[{"vertex":[{"lat_e7":389364691,"lng_e7":-923341133},{"lat_e7":389362067,"lng_e7":-923342783},{"lat_e7":389361075,"lng_e7":-923343356},{"lat_e7":389360594,"lng_e7":-923342477},

I've been working on this for hours, the closest I have come is finding a request uri that returns a result with a polygon in it. I believe it specifies the building(boundary) by editids parameter. We just need a way to get the current editids from a building(boundary).

The URI I have is:

https://www.google.com/mapmaker?hl=en&gw=40&output=jsonp&ll=38.934911%2C-92.329359&spn=0.016288%2C0.056477&z=14&mpnum=0&vpid=1354239392511&editids=nAlkfrzSpBMuVg-hSJ&xauth=YOUR_XAUTH_HERE&geowiki_client=mapmaker&hl=en

Part of the result has what is needed:

"polygon":[{"gnew":{"loop":[{"vertex":[{"lat_e7":389364691,"lng_e7":-923341133},{"lat_e7":389362067,"lng_e7":-923342783},{"lat_e7":389361075,"lng_e7":-923343356},{"lat_e7":389360594,"lng_e7":-923342477},
ぽ尐不点ル 2024-11-01 18:36:42

我对这个问题很感兴趣,并写了一个解决方案。请参阅我的 github 项目

I was intrigued on this problem and wrote a solution to it. See my github project.

梦魇绽荼蘼 2024-11-01 18:36:42

Google Maps API 包含 GeocoderResults 对象 这可能就是您所需要的。具体来说,是在geometry 字段中返回的数据。

The Google Maps API contains a GeocoderResults object that might be what you need. Specifically the data returned in the geometry field.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文