在Google Maps中验证点是土地还是水


106

..然后Google地图“将水与水分开”

好吧,不是圣经意义上的,而是

我想知道我可以使用哪些选项来验证[Lat,Lon]的点是土地还是水。

Google Maps显然具有此数据(水体为蓝色)-但是我可以在API中使用某些东西吗?如果不是-他们是否因为从未想过而没有提供服务?还是因为它太复杂?

除了这里的一些类似问题(例如查找地形类​​型或海拔高度,但这不是我所需要的)外,我没有找到任何有关此问题的信息。

是否有单独的图层?一个选项?命令?还是我应该手动去做?

我想到该方法的唯一方法(我需要手动执行此操作)是检查每个投放的图块的确切位置-然后检查该Google地图色相的RGB值。这只是理论上的-因为在实践中-我不知道如何完成该任务,第一个障碍是我不知道如何将图块上的像素位置转换为[LatLon]点

现成的解决方案将容易得多。

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

编辑我

看完评论后:高程方法不可靠,海平面以下的地方太多(您可以在此处http://geology.com/below-sea-level/上看到“最深”的10个列表)高于海平面(湖泊)的内陆水域过多。反向地理位置定位方法不可靠,因为它将多次返回地缘政治实体,例如城市或州或零。在提出问题之前,我已经研究过这些伪解决方案-但它们都没有真正回答问题-这些方法充其量是不好的“猜测”。


1
您也许可以使用高程库。尽管并非总是如此,但我想大多数时候海平面上的东西都会积水。有一些相当明显的极端情况(加利福尼亚死亡谷,荷兰,高山湖泊等),但它可能适用于大致的估计。

谢谢,我已经想到这一点-但像你指出的-有太多的点低于海平面在地球上-不包括所有的人是不是一个可行的解决方案..
Obmerk皇冠

@michael-更不用说您提到的所有内陆水域了(湖等)
Obmerk Kronen 2012年

也许更适合GIS.SE?您可以在赏金结束时进行迁移。
TMS

当你收到的回答,我没有什么可上说..但是,如果找水的数据,或者GIS信息,以及有一个单独的discussiong事情在我们单独的域http://gis.stackexchange.com/这里,您会发现许多您可能需要的东西,包括水数据..以防万一..(如果需要..)旧邮报我希望这会有所帮助..
MarmiK 2013年

Answers:


55

有两种不同的方法,您可以尝试:

  • 您可以使用Google地图反向地理编码。在结果集中,您可以通过检查确定是否为水types。在水域情况下,类型为natural_feature。在此链接http://code.google.com/apis/maps/documentation/geocoding/#Types中查看更多信息。

    另外,还需要检查要素名称(如果包含)Sea, Lake, Ocean以及与水有关的其他单词,以提高准确性。例如,沙漠也为natural_features。

    优点 -所有检测过程都将在客户端计算机上完成。无需创建自己的服务器端服务。

    缺点 -非常不准确,您在水域“无”的机会非常高。

  • 您可以使用Google静态地图按像素检测水域/陆地。但是为此,您需要创建http服务。

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

    1. 接收latitudelongitudecurrent zoom从客户端。
    2. http://maps.googleapis.com/maps/api/staticmap?center={纬度,经度}&zoom={当前缩放发送到Google静态地图服务。&size = 1x1&maptype = roadmap&sensor = false请求。
    3. 检测1x1静态图像的像素颜色。
    4. 响应有关检测的信息。

    您无法在客户端检测像素的颜色。是的,您可以在客户端计算机上加载静态图像并在canvas元素上绘制图像。但是您不能使用getImageData画布的上下文来获取像素的颜色。这受跨域策略的限制。

    Prons-高度准确的检测

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


2
谢谢-我已经检查过了-不知道类型正在转变为Sea Lake Ocean之类,并且就像您在编辑中指出的那样-natural_feature还将是一座山,一座岛屿和一片沙漠..也许指向文档?还-如何对没有地址的地方进行反向地理编码?那么作为地缘实体一部分的湖泊呢?像一个湖泊内的城市或直辖市的限制(例如genevre)或只是一个点至极里面是一个港口城市。在我的考验我已经zhcon失败这样做..
Obmerk皇冠

3
对于世界上大多数水域,反向地理编码将返回“零结果”,请查看地理编码工具:gmaps-samples-v3.googlecode.com/svn/trunk/geocoder/…,然后单击海洋中的某个位置。
Dr.Molle

@Tomas-不是我想对其他“堆叠者”表示不满或不尊重-但是也许它没有被投票,因为它不是有效/准确的方法?
Obmerk Kronen 2012年

3
以建议的方式使用静态地图可能会违反条款(10.1.1(h))。
Andrew Leach 2012年

1
至于“静态地图”方法,您可以使用样式developers.google.com/maps/documentation/static-maps/…来实现,但也可以使用链接到Saurav的文章。
miguev '16

19

当前的任何Google服务似乎都无法实现。

但是还有其他服务,例如Koordinates Vector JSON查询服务!您只需查询URL中的数据,然后返回JSON / XML响应

请求示例: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

您必须注册并提供密钥和选定的层号。您可以搜索其可用层的所有存储库。大多数图层仅是区域性的,但您也可以找到全球性的图层,例如世界海岸线

在此处输入图片说明

选择图层时,单击“服务”选项卡,将获得示例请求URL。我相信您只需要注册就可以了!

现在最好的:

您可以上传图层!

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


这看起来几乎是完美的,但是我看不到任何不是大洋洲的本地地图。有美国层吗?
HaloWebMaster 2013年

我提到的@HaloWebMaster层是全局的。您还可以按区域搜索图层。
TMS

@HaloWebMaster我刚刚注意到您可以上传自己的图层!查看我的更新。
TMS

嘿,托马斯,我不知道您是否真的得到了赏金(因为我已经离线一周了),但这太棒了!谢谢您的帮助,我将无法使我的应用程序正常运行。谢谢!(如果您没有得到赏金,我会奖励,仅PM PM)
HaloWebMaster

嘿,您为我节省了一周的自定义编码!这很值得!
HaloWebMaster

8

这是我使用的,而且效果还不错...如果您有更多的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;
}

代码无法在新版本上使用。如果($ red == 537 && $ green == 627 && $ blue == 765),新版本应该是这样的
Wim Pruiksma

8

有一个免费的Web API可以解决此问题,称为onwater.io。它不是Google地图内置的功能,但是在指定了经度和纬度的情况下,它会通过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(在水上工作的公司)工作。我们在水上建造自己解决此问题并为社区提供帮助。它是免费使用的(批量支付),我们想分享:)



1
它不再是免费的(用于更大容量),但是如果能够做到这一点,它仍然非常实惠!
Christian K.

文档页面显示错误。我想检查是否有特定于承保范围的数据?我的意思是您覆盖哪些国家?
nr5

onwater.io是否适用于湖泊和河流?如果是这样,我会得到类型的指示吗?
luksch

7

我认为在本地执行此查询会更有趣,因此我可以变得更加自力更生:假设我想一次生成25000个随机陆地坐标,而我想避免调用可能昂贵的外部API。这是我用TomSchober提到的python示例在python中进行的拍摄。基本上,它将在包含所有陆地坐标的预制350MB文件中查找坐标,如果坐标存在于其中,则将其打印出来。

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”文件,这是对OpenStreetMaps的补充。(我自己使用了第一个WGS84下载链接,也许第二个也可以使用)


湖泊呢?它会将湖泊上的点视为海洋还是陆地?
fatma.ekici

好问题!我在页面上检查了答案链接的OpenStreetMaps数据,并说lands文件的值基于标记natural=coastline。快速浏览可以使用此页面该页面专门指出海岸线标签实际上不适用于其术语中的湖泊。所以我要说,我的方法不能将湖泊识别为水,因为我使用的数据集没有。但是请自己尝试!
SylvainB

7

查看这篇文章。它不需要服务器即可准确检测出水中是否有东西。这是一种依赖Google Maps中自定义样式功能的黑客。


5

除了反向地理编码(如Molle博士所指出的那样,它还可能返回ZERO_RESULTS),您还可以使用Elevation服务。如果通过反向地理编码得到的结果为零,则获取位置的高程。通常,由于海床位于海平面以下,因此海数为负数。有一个完整的例子海拔服务。

请记住,由于Google无法提供此信息,因此任何其他方法都只是一种猜测,而猜测本质上是不准确的。但是,使用type反向地理编码返回的值或海拔高度(如果type不可用)将涵盖大多数情况。


感谢您的回答和示例链接(顺便说一句-对我而言,它在Opera中不起作用)-但我不能真正忽略所有土地和负面地区,而我的实验表明TYPE不可靠-很多次返回一个临近的地缘政治实体。必须有一些更精确的方法-“猜测”在这里似乎不是正确的方法。如果TYPE是可靠的-这本来是最好的解决方案-但却不是...而您却忽略了所有高于海平面的内陆水域...
Obmerk Kronen 2012年

3

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

我知道这不是一个非常令人满意的答案。尤其是对于那些向用户提供了单击地图以定义标记位置的功能的用户,这非常令人沮丧。


1
我同意-@ user1113426和@Andrew Leach建议的方法并不是真正的方法。最好告诉用户“不要点击蓝色区域” :-),但是要认真地对待-我很惊讶google不想发布这样的功能-即使是近似值-比“近似值”更好现在存在-就像您的指针一样-有时会“偷偷”到几百米远的位置。甚至我建议的方法都比较准确(太糟糕了,我不知道该如何实现。)
Obmerk Kronen

3

如果所有其他方法都失败了,您可以随时尝试检查该点的高程并保持一定距离-除了水以外,没有其他东西会完全平整。


谢谢,这是一个好主意,但是它在每个瀑布或河流峡谷上都会
严重

2

不幸的是,这个答案不在Google Maps API中,并且所引用的资源不是免费的,但是DynamicGeometry提供了一个Web服务,该服务公开了GetWaterOrLand接受纬度/经度对的操作(您可以在此处查看演示)。

我对这是如何实现的理解是通过使用水体形状文件。这些形状文件与Google Maps API的配合使用情况如何,但是您可以从链接的演示中获得一些见解。

希望能有所帮助。


2

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

如您所见,ideia与rebe100x基本相同,从Google静态地图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

这是一个简单的解决方案

由于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回应,并提供确切的座标,在这个回应中将包含两个重要的「键」:「值」对

["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]

and

["GeoObject"]["name"]

检查种类键,如果它==“ hydro”,则表明您位于水域之上,并且由于Google返回的结果为零,因此该水域很有可能是99.99%。海洋的名称将是上面的“名称”键。

这是我如何使用Ruby编写的此策略的示例

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

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

对于此示例,假设我们的坐标位于某处的湖泊中:

1.)首先使用Google对坐标进行反向地理编码。

2.)Google很可能会返回结果,该结果是附近土地上醒目的默认地址。在此结果中,它提供了返回地址的坐标,该坐标与您提供的地址不匹配。测量您提供的坐标与返回结果的坐标之间的距离(如果该坐标有很大不同(例如100码)),请使用Yandex执行辅助备份请求,并检查“ kind”键的值(如果存在)是“水”,那么您知道坐标位于水上。由于Google返回的结果与上述示例相反,因此这是内陆水域的可能性为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

关于许可的注意事项:据我所知,Google不允许您使用其数据在Google提供的地图以外的任何其他地图上显示。但是,Yandex的许可非常灵活,您可以使用其数据在Google地图上显示。

Yandex还具有每天50,000个免费请求的高速率限制,并且没有必需的API密钥。


1

通过使用Google Elevation API,我设法接近了。这是结果的图像:

结果截图

您会看到六边形几乎保留在陆地上,即使定义了一个在水上部分覆盖的矩形周长。在这种情况下,我从Google Maps本身进行了快速检查,并且陆地的最低标高约为8-9m,因此这是我的门槛。该代码主要是从Google文档和Stack Overflow复制/粘贴的,以下是全部内容:

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


仅供参考,您可以在以下位置找到Google Elevation API文档:developers.google.com/maps/documentation/javascript/elevation
dvas0004 2016年

2
这是可能使用的一个很好的例子。但它会在内陆水域上辉煌地失败(在链接的图像示例中为Lago di garda-Italy)。非常好的代码被认为可以用作其他解决方案的基础!
Obmerk Kronen

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{ }


0

作为Python的新手,我无法获得SylvainB的解决方案来与检查坐标是否在陆地上的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中工作,但是我梦a以求地获取了您需要安装的所有软件包,以至于陷入了python。


-3

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

举个例子

如果我们要确定一个点x是陆地还是水,那么

让我们检查点x与已知点y(陆地)之间的方向。如果确定方向/距离,则点x为陆地,否则为水。


您是否实际尝试过,还是只是假设“从水中煮饭”?
TMS

您如何处理桥梁?还是隧道?
Obmerk Kronen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.