首页 文章

验证Google Map 中的某个点是Land还是Water

提问于
浏览
97

..然后谷歌 Map “划分水域的水”

嗯,不是在圣经的意义上,但..

我想知道我有什么选择来验证[Lat,Lon]的点是土地还是水 .

谷歌 Map 显然有这些数据(水体是蓝色的) - 但是我可以使用API中的某些东西吗?如果没有 - 他们是不是因为他们没有想到它而服务它?还是因为它太复杂了?

我没有找到任何关于这个问题的信息 - 除了一些类似的问题(比如寻找地形类型或海拔 - 但这不是我需要的) .

那有分离的层吗?一个选项?命令?或者我应该手动去做?

我能想到如何处理这个问题的唯一方法(我是否需要手动执行)是检查每个服务的磁贴的确切点 - 然后检查该Google Map 色调的RGB值 . 这只是在理论上 - 因为在实践中 - 我不知道如何实现这一点,第一个障碍是我不知道如何将瓷砖上的像素位置转换为[LatLon]点,例如

现成的解决方案会更容易 .

请注意,我不需要世界上所有的水(例如 - 我不关心溪流,小池塘,大多数河流或邻居的游泳池 . 我需要一个人可以在没有浮动车辆的情况下冒险的地方)

EDIT I

阅读评论后:提升方法不可靠,海平面以下有太多地方(你可以在这里看到"deepest" 10的列表http://geology.com/below-sea-level/)并且海平面(湖泊)上面有太多内陆水体 . 反向地理定位方法不可靠,因为它会多次返回地理政治实体,如城市或州 - 或ZERO . 在问这个问题之前我已经研究了那些伪解决方案 - 但是他们中没有一个真正回答了这个问题 - 这些方法充其量也很糟糕"guessing" .

18 回答

  • 7

    这些是两种不同的方式,您可以尝试:

    此外,您还需要检查要素的名称,如果它们包含 Sea, Lake, Ocean 以及其他与水相关的单词以获得更高的准确性 . 例如,沙漠也是 natural_feature .

    Prons - 所有检测过程都将在客户端的机器上完成 . 无需创建自己的服务器端服务 .

    Cons - 非常不准确,你在水域获得"none"的可能性非常高 .

    • 您可以使用Google Static Maps按像素检测水域/土地 . 但为此您需要创建http服务 .

    这些是您的服务必须执行的步骤:

    • 从客户端收到 latitudelongitudecurrent zoom .

    • 发送 http://maps.googleapis.com/maps/api/staticmap?center={ 纬度 , 经度 }&zoom={ 当前缩放`}&size = 1x1&maptype = roadmap&sensor = false请求Google静态 Map 服务 .

    • 检测1x1静态图像的像素颜色 .

    • 回复有关检测的信息 .

    您可以在客户端使用't detect pixel'的颜色 . 是的,您可以在客户端的计算机上加载静态图像并在 canvas 元素上绘制图像 . 但你不能使用's context for getting pixel'的颜色's context for getting pixel' . 这受跨域策略的限制 .

    Prons - 高度准确的检测

    Cons - 使用自己的服务器资源进行检测

  • 5

    目前任何Google服务似乎都无法做到这一点 .

    但还有其他服务,比如 Koordinates Vector JSON Query service !您只需查询URL中的数据,然后查询 you get back a JSON/XML response .

    示例请求:http://api.koordinates.com/api/vectorQuery.json?key = YOUR_GEODATA_KEY&layer = 1298&x = -159.9609375&y = 13.239945499286312&max_results = 3&radius = 10000&geometry = true&with_field_names = true

    您必须注册并提供您的密钥和选定的图层编号 . 你可以搜索他们所有的repository of available layers . 大多数图层只是区域性的,但您也可以找到全局图,例如World Coastline

    enter image description here

    选择图层后,单击“服务”选项卡,即可获得示例请求URL . 我相信你只需要注册,就是这样!

    而现在最好的:

    您可以上传图层!

    它不能立即使用,嘿必须以某种方式处理它,但它应该工作!层存储库实际上看起来像人们根据需要上传它们 .

  • 2

    这就是我使用它并且工作不是太糟糕...如果你有更多的cpu浪费,你可以改进测试添加像素 .

    function isItWatter($lat,$lng) {
    
        $GMAPStaticUrl = "https://maps.googleapis.com/maps/api/staticmap?center=".$lat.",".$lng."&size=40x40&maptype=roadmap&sensor=false&zoom=12&key=YOURAPIKEY";  
        //echo $GMAPStaticUrl;
        $chuid = curl_init();
        curl_setopt($chuid, CURLOPT_URL, $GMAPStaticUrl);   
        curl_setopt($chuid, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($chuid, CURLOPT_SSL_VERIFYPEER, FALSE);
        $data = trim(curl_exec($chuid));
        curl_close($chuid);
        $image = imagecreatefromstring($data);
    
        // this is for debug to print the image
        ob_start();
        imagepng($image);
        $contents =  ob_get_contents();
        ob_end_clean();
        echo "<img src='data:image/png;base64,".base64_encode($contents)."' />";
    
        // here is the test : I only test 3 pixels ( enough to avoid rivers ... )
        $hexaColor = imagecolorat($image,0,0);
        $color_tran = imagecolorsforindex($image, $hexaColor);
    
        $hexaColor2 = imagecolorat($image,0,1);
        $color_tran2 = imagecolorsforindex($image, $hexaColor2);
    
        $hexaColor3 = imagecolorat($image,0,2);
        $color_tran3 = imagecolorsforindex($image, $hexaColor3);
    
        $red = $color_tran['red'] + $color_tran2['red'] + $color_tran3['red'];
        $green = $color_tran['green'] + $color_tran2['green'] + $color_tran3['green'];
        $blue = $color_tran['blue'] + $color_tran2['blue'] + $color_tran3['blue'];
    
        imagedestroy($image);
        var_dump($red,$green,$blue);
        //int(492) int(570) int(660) 
        if($red == 492 && $green == 570 && $blue == 660)
            return 1;
        else
            return 0;
    }
    
  • 2

    查看这篇文章 . 它可以准确地检测水中是否有东西,而无需服务器 . 这是一个依赖谷歌 Map 中自定义样式功能的黑客 .

    http://tech.bellycard.com/blog/where-d-the-water-go-google-maps-water-pixel-detection-with-canvas/

  • 0

    我觉得在本地进行这个查询更有意思,所以我可以更自觉:假设我想一次生成25000个随机陆地坐标,我宁愿避免调用可能代价高昂的外部API . 这是我在python中的镜头,使用了TomSchober提到的python example . 基本上它查找包含所有陆地坐标的pre-made 350MB file上的坐标,如果坐标存在于那里,则打印它们 .

    import ogr
    from IPython import embed
    import sys
    
    drv = ogr.GetDriverByName('ESRI Shapefile') #We will load a shape file
    ds_in = drv.Open("land_polygons.shp")    #Get the contents of the shape file
    lyr_in = ds_in.GetLayer(0)    #Get the shape file's first layer
    
    #Put the title of the field you are interested in here
    idx_reg = lyr_in.GetLayerDefn().GetFieldIndex("P_Loc_Nm")
    
    #If the latitude/longitude we're going to use is not in the projection
    #of the shapefile, then we will get erroneous results.
    #The following assumes that the latitude longitude is in WGS84
    #This is identified by the number "4236", as in "EPSG:4326"
    #We will create a transformation between this and the shapefile's
    #project, whatever it may be
    geo_ref = lyr_in.GetSpatialRef()
    point_ref=ogr.osr.SpatialReference()
    point_ref.ImportFromEPSG(4326)
    ctran=ogr.osr.CoordinateTransformation(point_ref,geo_ref)
    
    def check(lon, lat):
        #Transform incoming longitude/latitude to the shapefile's projection
        [lon,lat,z]=ctran.TransformPoint(lon,lat)
    
        #Create a point
        pt = ogr.Geometry(ogr.wkbPoint)
        pt.SetPoint_2D(0, lon, lat)
    
        #Set up a spatial filter such that the only features we see when we
        #loop through "lyr_in" are those which overlap the point defined above
        lyr_in.SetSpatialFilter(pt)
    
        #Loop through the overlapped features and display the field of interest
        for feat_in in lyr_in:
            # success!
            print lon, lat
    
    check(-95,47)
    

    我尝试了十几个坐标,效果非常好 . "land_polygons.shp"文件可以下载here,OpenStreetMaps的赞美 . (我自己使用了第一个WGS84下载链接,也许第二个工作也是如此)

  • 54

    有一个免费的Web API可以解决这个问题onwater.io . 它不是内置于Google Map 中的内容,但考虑到纬度和经度,它将通过get请求准确地返回true或false .

    关于水的例子:https://api.onwater.io/api/v1/results/23.92323,-66.3

    {
      lat: 23.92323,
      lon: -66.3,
      water: true
    }
    

    土地上的例子:https://api.onwater.io/api/v1/results/42.35,-71.1

    {
      lat: 42.35,
      lon: -71.1,
      water: false
    }
    

    完全披露我在Dockwa.com工作,该公司背后的onwater . 我们 Build onwater以自己解决这个问题并帮助社区 . 它是免费使用(支付高容量),我们想分享:)

  • 6

    除了反向地理编码 - 正如Dr Molle指出的那样,它可能会返回ZERO_RESULTS - 您可以使用Elevation服务 . 如果通过反向地理编码获得零结果,请获取该位置的高程 . 由于海床低于海平面,海洋通常为负数 . 在http://www.daftlogic.com/sandbox-google-maps-find-altitude.htm有一个完整的高程服务示例 .

    请记住,由于谷歌不提供这些信息,任何其他方法只是一种猜测,猜测本质上是不准确的 . 但是,使用反向地理编码返回的 typetype 不可用时的高程将覆盖大多数可能性 .

  • 2

    这种方法完全不可靠 . 实际上,返回的数据完全取决于您正在使用的世界的哪个部分 . 例如,我在法国工作 . 如果我点击法国海岸的大海,谷歌将返回它可以“猜测”的最近的LAND位置 . 当我向Google请求同一问题的信息时,他们回答说他们无法准确地返回水团所要求的点数 .

    我知道,答案不是很理想 . 这非常令人沮丧,特别是对于那些为用户提供点击 Map 以定义标记位置的人 .

  • 8

    如果所有其他方法都失败了,你总是可以尝试检查该点的高度和一些距离 - 除水以外的其他东西往往是完全平坦的 .

  • 3

    不幸的是,这个答案不是由DynamicGeometry提供的Web服务,它公开了一个接受纬度/经度对(you can see a demo here)的操作 GetWaterOrLand .

    我对如何实现这一点的理解是使用水体形状文件 . 这些形状文件究竟与Google Maps API一起使用,但您可以从链接的演示中获得一些见解 .

    希望在某种程度上有所帮助 .

  • -2

    这是纯JavaScript中的另一个例子:http://jsfiddle.net/eUwMf/

    如您所见,ideia与rebe100x基本相同,从Google静态 Map API获取图像,并读取第一个像素:

    $("#xGps, #yGps").change(function() {
        var img = document.getElementById('mapImg');
    
        // Bypass the security issue : drawing a canvas from an external URL.
        img.crossOrigin='anonymous';
    
        var xGps = $("#xGps").val();
        var yGps = $("#yGps").val();
    
        var mapUrl = "http://maps.googleapis.com/maps/api/staticmap?center=" + xGps + "," + yGps +
            "&zoom=14&size=20x20&maptype=roadmap&sensor=false";
    
        // mapUrl += "&key=" + key;
    
        $(img).attr("src", mapUrl);
    
        var canvas = $('<canvas/>')[0];
        canvas.width = img.width;
        canvas.height = img.height;
        canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
    
        var pixelData = canvas.getContext('2d').getImageData(1, 1, 1, 1).data;
    
        if (pixelData[0] == 164 &&
            pixelData[1] == 190 &&
            pixelData[2] == 220) {
            $("#result").html("Water");
        } else {
            $("#result").html("Not water");
        }
    });
    
  • 1

    See the answer I gave to a similar question - 它使用来自地球Api的"HIT_TEST_TERRAIN"来实现该功能 .

    我在这里提出了一个有关这个想法的工作示例:http://www.msa.mmu.ac.uk/~fraser/ge/coord/

  • 2

    我建议你自己滚动 . 您可以使用GDAL等工具查询shapefile中某个点下的内容 . 您可以从许多来源获得美国地理的shapefile,包括US Census Bureau .

    这可以通过GDAL二进制文件,源代码C或Java,Python等swig来完成 .

    Census Maps

    GDAL Information

    Point Query Example in Python

  • 7

    通过使用Google Elevation API,我成功了 . 这是结果的图像:

    screenshot of results

    你可以看到六边形几乎停留在陆地上,即使一个矩形周边定义为部分在水面上 . 在这种情况下,我从谷歌 Map 本身做了一个快速检查,陆地上的最小高度约为8-9米,这是我的门槛 . 代码主要是从Google文档和Stack中复制/粘贴的溢出,这是完整的要点:

    https://gist.github.com/dvas0004/fd541a0502528ebfb825

  • 2

    这是一个简单的解决方案

    由于Google无法提供有关海洋或内陆水域坐标的可靠结果,因此您需要使用其他备份服务(如Yandex)来帮助提供缺失时的重要信息 . 您很可能不希望使用Yandex作为主要的地理编码器,因为Google在世界数据的可靠性和完整性方面要优越得多,但是Yandex在与水体坐标相关时检索数据非常有用,所以两者兼用 .


    Yandex文档:https://api.yandex.com.tr/maps/doc/geocoder/desc/concepts/input_params.xml


    检索海洋名称的步骤:

    1.)首先使用Google来反转地理编码坐标 .

    2.)如果Google返回零结果,则坐标位于海洋上的可能性为99% . 现在使用与Yandex相同的坐标进行二次反向地理编码请求 . Yandex将返回一个具有精确坐标的JSON响应,在此响应中将是两个“key”:“value”对的重要性

    ["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]
    
    and
    
    ["GeoObject"]["name"]
    

    检查实物密钥,如果它=“水电”,你知道你已经在水体上,并且由于谷歌返回零结果,这个水体可能是海洋的99.99% . 海洋的名称将是上面的“名称”键 .

    这是我如何使用Ruby编写的这个策略的一个例子

    if result.data["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"] == "hydro"
         ocean = result.data["GeoObject"]["name"] 
    end
    

    检索内陆水体名称的步骤:

    对于这个例子,假设我们的坐标位于一个湖泊的某个地方:

    1.)首先使用Google来反转地理编码坐标 .

    2.)谷歌很可能会返回一个在附近土地上的突出默认地址的结果 . 在此结果中,它提供了它返回的地址的坐标,该坐标与您提供的坐标不匹配 . 测量您提供的坐标与返回的坐标之间的距离,如果它有显着差异(例如100码),则使用Yandex执行辅助备份请求并检查“kind”键的值,如果它是“水力”然后你知道坐标在水面上 . 因为谷歌返回了一个结果而不是上面的例子,所以这是一个内陆水域的99.99%,所以现在你可以得到这个名字 . 如果“kind”不= =“hydro”,则使用Google地理编码对象 .

    ["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]
    
    and
    
    ["GeoObject"]["name"]
    

    这是用Ruby编写的相同代码来获取inland_body_of_water

    if result.data["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"] == "hydro"
         inland_body_of_water = result.data["GeoObject"]["name"] 
    end
    

    关于许可的说明:据我所知,谷歌不允许您使用他们的数据显示在谷歌提供的任何其他 Map 上 . 然而,Yandex具有非常灵活的许可,您可以使用他们的数据在Google Map 上显示 .

    此外,Yandex的免费使用率高达50,000请求,并且没有必需的API密钥 .

  • 1

    如果 List<Address> 地址返回0,您可以将此位置视为海洋或自然资源 . 只需在您的响应中添加以下代码Google Places API响应方法 .

    如上所述初始化下面的列表

    List<Address> addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1);

    if (addresses.size()==0) { Toast.MakeText(getApplicationContext,"Ocean or Natural Resources selected",Toast.LENGTH_SHORT).show(); }else{ }

  • 19

    作为Python的完全新手,我无法使用python脚本来检查坐标是否在陆地上 . 然而,我设法弄清楚了,通过下载OSGeo4W(https://trac.osgeo.org/osgeo4w/),然后安装了我需要的所有东西pip,Ipython,并检查指定的所有导入都在那里 . 我将以下代码保存为.py文件 .

    用于检查坐标是否在陆地上的代码

    ###make sure you check these are there and working separately before using the .py file 
    
    import ogr
    from IPython import embed
    from osgeo import osr
    import osgeo
    
    import random
    #####generate a 1000 random coordinates
    ran1= [random.uniform(-180,180) for x in range(1,1001)]
    ran2= [random.uniform(-180,180) for x in range(1,1001)]
    
    
    drv = ogr.GetDriverByName('ESRI Shapefile') #We will load a shape file
    ds_in = drv.Open("D:\Downloads\land-polygons-complete-4326\land-polygons-complete-4326\land_polygons.shp")    #Get the contents of the shape file
    lyr_in = ds_in.GetLayer(0)    #Get the shape file's first layer
    
    #Put the title of the field you are interested in here
    idx_reg = lyr_in.GetLayerDefn().GetFieldIndex("P_Loc_Nm")
    
    #If the latitude/longitude we're going to use is not in the projection
    #of the shapefile, then we will get erroneous results.
    #The following assumes that the latitude longitude is in WGS84
    #This is identified by the number "4236", as in "EPSG:4326"
    #We will create a transformation between this and the shapefile's
    #project, whatever it may be
    geo_ref = lyr_in.GetSpatialRef()
    point_ref=osgeo.osr.SpatialReference()
    point_ref.ImportFromEPSG(4326)
    ctran=osgeo.osr.CoordinateTransformation(point_ref,geo_ref)
    ###check if the random coordinates are on land
    def check(runs):
        lon=ran1[runs]
        lat=ran2[runs]
        #Transform incoming longitude/latitude to the shapefile's projection
        [lon,lat,z]=ctran.TransformPoint(lon,lat)
        #Create a point
        pt = ogr.Geometry(ogr.wkbPoint)
        pt.SetPoint_2D(0, lon, lat)
        #Set up a spatial filter such that the only features we see when we
        #loop through "lyr_in" are those which overlap the point defined above
        lyr_in.SetSpatialFilter(pt)
        #Loop through the overlapped features and display the field of interest
        for feat_in in lyr_in:
            return(lon, lat)
    
    ###give it a try
    result = [check(x) for x in range(1,11)] ###checks first 10 coordinates
    

    我试图让它在R中工作,但我有一个噩梦试图获得你需要安装的所有软件包,所以坚持python .

  • 3

    我这里有一个不同的解决方案 . 在当前的谷歌 Map 实施中,它不计算从水位到陆地位置的方向/距离,反之亦然 . 为什么我们不使用这个逻辑来确定这个点是土地还是水 .

    例如,让我们举个例子

    如果我们想确定,如果一个点是土地或水,那么

    让我们检查点 x 和已知点 y 之间的方向 . 如果它确定了方向/距离,则点 x 是陆地,否则它是水 .

相关问题