跳到主要内容
实操指南10 分钟阅读

开采之前:如何审计 Google 街景的覆盖范围与影像时效

元数据请求免费,且不消耗影像配额。先跑一遍,就能把「这里到底有没有覆盖」从一个假设变成一个测出来的数字。

作者
HuiTu Technology
发布时间
更新时间

要发现一个研究区域的街景覆盖其实千疮百孔,最贵的方式是在影像采集跑到一半时才发现。第二贵的方式,是在分析阶段才发现——那时你才看到,三分之一的采样点用的是分属三个年份的影像。

其实有一条便宜得多的路。Street View Static API 提供了一个元数据端点,可以回答某个位置有没有影像、最近的全景实际落在哪里、大致什么时候拍的。Google 的文档明确说明这类请求免费,且不消耗影像配额——这意味着把一整座城市的覆盖度审计跑完,成本只有请求时间。把它放在最前面做,是街景项目中回报率最高的一小时。

元数据端点会返回什么

你发送的参数和请求影像时一样:位置、半径、来源类型。拿回来的不是一张 JPEG,而是一个很小的 JSON 对象。

一次成功响应中的字段
字段它告诉你什么我们怎么用它
status是否找到了全景;没找到的话,是什么原因覆盖标记本身;其余字段都以它为前提
location被匹配到的那个全景的经纬度吸附距离:返回的全景离你查询的点有多远
date拍摄月份,通常为 YYYY-MM 形式影像年龄、季节控制,以及整批采样的年份一致性
pano_id被匹配全景的标识符单次运行内去重,以及两次运行之间的更替检测
copyright该全景的署名信息区分平台官方采集与用户贡献的全景

发第一个请求之前,先把采样设计定好

覆盖审计本质上是一次抽样,而设计糟糕的抽样只会给出一个自信的错误答案。三个决定几乎决定了全部结果。

  • 沿路网采样,不要用方形格网。格网会把点撒到街区内部和公园中央——那里本来就不该有全景——然后把由此产生的空白算成覆盖缺失。
  • 固定一个间距并记录下来。城市场景通常取 20 到 50 米。凡是你打算相互比较的行政区,间距必须完全一致,否则覆盖率之间没有可比性。
  • 半径要有意识地设定。半径放宽会让覆盖率显得很漂亮,因为它会匹配到离查询点很远的全景;半径收紧更诚实,但会在宽阔道路上误拒合理匹配。我们通常取 30 米,并把吸附距离一并保留,以便日后重新审视这个选择。

来源参数同样重要。指定只要室外影像,可以排除室内全景——否则恰好落在采样点附近的商铺内部和车站大厅,会污染整个街道景观审计。

一段最小可用的审计脚本

不需要任何花活:读入点位、逐点探测、每点写一行,并且把响应给出的每个字段都原样留下,而不是在写入时就压缩成一个布尔值。

import csv
import os
import time

import requests

API = "https://maps.googleapis.com/maps/api/streetview/metadata"
KEY = os.environ["GOOGLE_MAPS_API_KEY"]  # never hard-code a key into the script

session = requests.Session()


def probe(lat, lon, radius=30, source="outdoor"):
    """Metadata request: free of charge, and it consumes no image quota."""
    params = {
        "location": f"{lat},{lon}",
        "radius": radius,      # snap distance in metres; keep it tight
        "source": source,      # "outdoor" excludes indoor and interior panoramas
        "key": KEY,
    }
    for attempt in range(4):
        response = session.get(API, params=params, timeout=10)
        if response.status_code == 200:
            return response.json()
        time.sleep(2 ** attempt)   # back off, then retry
    return {"status": "REQUEST_FAILED"}


with open("sample_points.csv") as source_file, \
     open("coverage.csv", "w", newline="") as out_file:
    writer = csv.writer(out_file)
    writer.writerow(
        ["point_id", "status", "pano_id", "capture_month", "pano_lat", "pano_lon"]
    )
    for row in csv.DictReader(source_file):
        meta = probe(row["lat"], row["lon"])
        located = meta.get("location") or {}
        writer.writerow([
            row["point_id"],
            meta.get("status"),
            meta.get("pano_id", ""),
            meta.get("date", ""),          # YYYY-MM, when the platform returns it
            located.get("lat", ""),
            located.get("lng", ""),
        ])

有两个习惯值得从任何采集流水线沿用过来:绝不把密钥硬编码进脚本,以及保留原始状态码而不是过早把它折叠掉。一次只记录了「有覆盖/无覆盖」的运行,事后无法区分真正的覆盖缺口和悄悄撞上配额上限的请求。

认真读 status 字段

各状态码在审计中的真实含义
状态含义正确处理方式
OK在半径内找到了全景记录下来,并记录吸附距离
ZERO_RESULTS请求位置附近没有全景真正的覆盖缺口,按缺口计入
NOT_FOUND位置或全景 ID 无法解析回头检查输入;不要和真实缺口混为一谈
OVER_QUERY_LIMIT触发了频率或用量限制退避后重试;绝不能计为覆盖缺口
REQUEST_DENIED请求未获授权这是配置问题而非数据结论;应中止本次运行
INVALID_REQUEST必填参数缺失或格式错误修调用方;这些行不构成关于覆盖的任何证据

一次审计应当产出哪些数字

把响应表变成一小组可以直接摆到出资方面前的指标。下面这些,是真正会改变决策的那几个。

  • 覆盖率:返回 OK 的采样点占比,要按行政区和道路等级分别报告,而不是给一个总的头条数字。
  • 吸附距离的中位数,以及第 90 百分位。尾部抬高意味着系统正在从相邻街道上给你匹配全景。
  • 影像年龄分布:拍摄月份中位数,以及超出你时效阈值的比例。
  • 每个比较单元内部的年份跨度。一个点位横跨 2019 到 2026 的行政区,无法与另一个整体拍摄于 2025 的行政区干净地比较。
  • 拍摄月份构成,它是后续任何植被指标都会需要的季节控制变量。
  • 唯一全景数与采样点数之比。这个比值远小于一,说明你的采样间距细于全景本身的间隔,你在为重复内容付费。
纽约第五大道的 360 度街景全景,画面中有建筑、车流与行人
一个 OK 状态背后的全景。审计并不会去取这张图,它只确认这张图存在、位置在哪、什么时候拍的——在任何影像请求产生费用之前。

时效是项目约束,不是细节

拍摄月份是最常被一眼扫过、事后又最让人后悔的字段。临街商铺的更替速度足够快,四年前的影像会把「现在在营业的是谁」讲错。用一月落叶期影像算出来的植被指标,和七月的完全没有可比性,而这个差距通常比你所研究的各条街道之间的差异还要大。

同一采样点在 2026 年 4 月拍摄的街景全景
单个点位的某一个拍摄月份。正是元数据里的 date 字段,让你可以在分析之前按年份给点位分组,而不是分析完了才发现里面混着好几个年份。

全景 ID 会变,要为此做设计

全景 ID 标识的是「平台这次给你的那份影像」,而不是「这个地点」。平台会重拍街道、重新处理全景、下线旧数据,因此某次审计里记下的 ID,过一段时间可能就解析不出来了。请把它当作单次运行内的值:用于本轮去重,而你自己的数据库仍以采样点标识符为主键。两次审计之间 ID 发生变化,只能作为待复核标记;还要同时检查拍摄日期和返回位置,才能判断是不是发布了新影像,因为重新处理同样可能改变标识符。

报告要写到让决策一目了然

  1. 在最上面写明采样间距、半径与来源参数。没有它们,覆盖率就是一个没有定义的数字。
  2. 覆盖率按行政区和道路等级拆开,因为缺口几乎从不均匀分布。
  3. 影像年龄用拍摄月份的直方图呈现,而不是给一个平均值。
  4. 标出未通过时效或年份一致性阈值的比较单元,并为它们的替代方案单独报价。
  5. 直接用 OK 的数量估算影像请求量与费用——此时它已经是一个测量值,而不是一个猜测。

一次好的审计,其结论往往是把项目做小:与其五个行政区都覆盖得参差不齐,不如三个行政区覆盖扎实。这个结果,总好过等账单寄到之后才发现同一件事。

更多文章

继续阅读

下一步

比起了解方法,更想直接把事做完?

如果文章里描述的问题正好是你遇到的,把具体情况发来,我们会给出工作范围与固定报价。