Skip to main content

A Python library for verifying Google Street View panorama existence and calibrating OCR bounding boxes through perspective re-projection.

Project description

gsv-ocr-check

A Python library for verifying Google Street View panorama existence and calibrating OCR bounding boxes through perspective re-projection.

Features

  • Panorama Existence Check: Verify whether a Google Street View panorama ID is still accessible
  • Panorama Download: Download panoramas to disk or into memory as PIL Images
  • OCR Bounding Box Calibration: Refine OCR coordinates by re-running OCR on perspective crops at multiple fields of view
  • Engine Agnostic: Works with any panoocr-compatible OCR engine
  • Async Support: Both sync and async APIs for panorama operations

Installation

Install the base package:

pip install gsv-ocr-check

Install with macOS OCR support:

pip install "gsv-ocr-check[macocr]"

Using uv (recommended):

uv add gsv-ocr-check
uv add "gsv-ocr-check[macocr]"

Quick Start

from gsv_ocr_check import check_panorama_exists, calibrate_ocr, download_panorama
from panoocr.engines.macocr import MacOCREngine

# 1. Check if a panorama still exists on Google Street View
exists = check_panorama_exists("abc123")

# 2. Download the panorama
image = download_panorama("abc123", output_path="pano.jpg")

# 3. Calibrate an OCR bounding box
engine = MacOCREngine()
result = calibrate_ocr(
    panorama="pano.jpg",
    target_text="LOVE",
    yaw=38.5,
    pitch=-2.4,
    engine=engine,
)

if result:
    print(f"Text: {result.text}")
    print(f"Position: yaw={result.yaw:.2f}°, pitch={result.pitch:.2f}°")
    print(f"Size: {result.width:.2f}° x {result.height:.2f}°")
    print(f"Confidence: {result.confidence}")
    print(f"FOV used: {result.fov_used}°")

API

Panorama Operations

check_panorama_exists(panorama_id) -> bool

Check if a Google Street View panorama still exists. Returns True if accessible, False otherwise.

from gsv_ocr_check import check_panorama_exists

if check_panorama_exists("UVfBLpzNhpZdImXJqozDmg"):
    print("Panorama is still available")

download_panorama(panorama_id, output_path=None, zoom=5, quality=95) -> Image | None

Download a panorama image. Returns a PIL Image, or None if the panorama is not found.

from gsv_ocr_check import download_panorama

# Download to memory only
image = download_panorama("abc123")

# Download and save to disk
image = download_panorama("abc123", output_path="panoramas/abc123.jpg")

# Download at lower resolution (zoom 0-5)
image = download_panorama("abc123", zoom=2)

Async Variants

Both functions have async counterparts for use in async contexts:

from gsv_ocr_check import check_panorama_exists_async, download_panorama_async

exists = await check_panorama_exists_async("abc123")
image = await download_panorama_async("abc123", output_path="pano.jpg")

OCR Calibration

calibrate_ocr(panorama, target_text, yaw, pitch, engine, **kwargs) -> CalibrationResult | None

Refine an OCR bounding box by generating perspective views centered on the original detection, re-running OCR, and returning the best match in spherical coordinates.

from gsv_ocr_check import calibrate_ocr
from panoocr.engines.macocr import MacOCREngine

engine = MacOCREngine()
result = calibrate_ocr(
    panorama="pano.jpg",       # path or PIL Image
    target_text="LOVE",        # exact match, case-insensitive
    yaw=38.5,                  # original detection yaw
    pitch=-2.4,                # original detection pitch
    engine=engine,             # any panoocr-compatible engine
)

Parameters:

Parameter Type Default Description
panorama str | Path | Image required Path to equirectangular panorama or PIL Image
target_text str required Text to match (exact, case-insensitive)
yaw float required Original detection yaw in degrees
pitch float required Original detection pitch in degrees
engine object required panoocr-compatible OCR engine
panorama_id str None ID for naming saved perspective files
fovs list[float] [45, 90, 120] FOVs to try in order
resolution int 2048 Perspective image resolution in pixels
save_perspectives str | Path None Directory to save perspective crops

CalibrationResult

Dataclass returned by calibrate_ocr with the refined detection:

@dataclass
class CalibrationResult:
    text: str              # Matched text
    confidence: float      # OCR confidence score
    yaw: float             # Refined yaw in degrees
    pitch: float           # Refined pitch in degrees
    width: float           # Angular width in degrees
    height: float          # Angular height in degrees
    engine: str            # OCR engine class name
    match_type: str        # "exact"
    original_yaw: float    # Input yaw (preserved)
    original_pitch: float  # Input pitch (preserved)
    fov_used: float        # FOV that produced the match
    resolution_used: int   # Resolution used

How Calibration Works

  1. Load the equirectangular panorama image
  2. Generate a perspective view centered on the original yaw/pitch coordinates
  3. Try multiple FOVs in sequence (default: 45° → 90° → 120°) — narrow FOV gives better resolution, wider FOV captures more context
  4. Run OCR on each perspective image
  5. Filter for exact text matches (case-insensitive)
  6. Select the match closest to the image center
  7. Transform pixel coordinates back to spherical using panoocr.geometry.perspective_to_sphere
  8. Return the first successful match, or None if no match at any FOV

Advanced Usage

Custom OCR Engine

Any object with a recognize(pil_image) method returning results with .text, .confidence, and .bounding_box attributes works:

from panoocr.engines.easyocr import EasyOCREngine

engine = EasyOCREngine(config={"language_preference": ["en"]})
result = calibrate_ocr("pano.jpg", "HELLO", yaw=0, pitch=0, engine=engine)

Saving Perspective Crops

Save the perspective images generated during calibration for debugging:

result = calibrate_ocr(
    panorama="pano.jpg",
    target_text="LOVE",
    yaw=38.5,
    pitch=-2.4,
    engine=engine,
    save_perspectives="debug/perspectives/",
)
# Saves: debug/perspectives/<pano_id>_fov45.jpg, etc.

Custom FOVs and Resolution

result = calibrate_ocr(
    panorama="pano.jpg",
    target_text="LOVE",
    yaw=38.5,
    pitch=-2.4,
    engine=engine,
    fovs=[30.0, 60.0, 90.0],  # custom FOV sequence
    resolution=4096,            # higher resolution perspective
)

Using PIL Images Directly

from PIL import Image

image = Image.open("pano.jpg")
result = calibrate_ocr(
    panorama=image,
    target_text="LOVE",
    yaw=38.5,
    pitch=-2.4,
    engine=engine,
    panorama_id="my_pano",  # required when passing PIL Image
)

Coordinate System

All coordinates use spherical (yaw, pitch) format:

  • Yaw: Horizontal angle in degrees, normalized to [-180, 180]
  • Pitch: Vertical angle in degrees (-90 to 90)
  • Width/Height: Angular dimensions in degrees

Dependencies

  • streetlevel — Google Street View panorama access
  • panoocr — Perspective projection, coordinate transforms, OCR engines
  • Pillow — Image handling

License

MIT License — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gsv_ocr_check-0.1.0.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gsv_ocr_check-0.1.0-py3-none-any.whl (8.1 kB view details)

Uploaded Python 3

File details

Details for the file gsv_ocr_check-0.1.0.tar.gz.

File metadata

  • Download URL: gsv_ocr_check-0.1.0.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gsv_ocr_check-0.1.0.tar.gz
Algorithm Hash digest
SHA256 55e765e4ed6e1aa289d137dfb864757770ff96d83182d1680b2b2e17508a0edc
MD5 9eb77cad51f366539bc632ce4d09a14c
BLAKE2b-256 0350a7345c0a5cdab1b2c3db382f25b12d57e0817bf7605df05839b7699d3b6d

See more details on using hashes here.

Provenance

The following attestation bundles were made for gsv_ocr_check-0.1.0.tar.gz:

Publisher: publish.yml on yz3440/gsv-ocr-check

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gsv_ocr_check-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gsv_ocr_check-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gsv_ocr_check-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5cb44382c6539673c841521bc1150f2a33c1fe79601d363329e8b5385b83fcef
MD5 ff344e86931279e7b9232d8d0c8ed73d
BLAKE2b-256 dfed60ebba28a6cbcd386442e4ee6c0c46b6da2bcf581d6fbb4c9354c00abc03

See more details on using hashes here.

Provenance

The following attestation bundles were made for gsv_ocr_check-0.1.0-py3-none-any.whl:

Publisher: publish.yml on yz3440/gsv-ocr-check

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page