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
- Load the equirectangular panorama image
- Generate a perspective view centered on the original yaw/pitch coordinates
- Try multiple FOVs in sequence (default: 45° → 90° → 120°) — narrow FOV gives better resolution, wider FOV captures more context
- Run OCR on each perspective image
- Filter for exact text matches (case-insensitive)
- Select the match closest to the image center
- Transform pixel coordinates back to spherical using
panoocr.geometry.perspective_to_sphere - Return the first successful match, or
Noneif 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55e765e4ed6e1aa289d137dfb864757770ff96d83182d1680b2b2e17508a0edc
|
|
| MD5 |
9eb77cad51f366539bc632ce4d09a14c
|
|
| BLAKE2b-256 |
0350a7345c0a5cdab1b2c3db382f25b12d57e0817bf7605df05839b7699d3b6d
|
Provenance
The following attestation bundles were made for gsv_ocr_check-0.1.0.tar.gz:
Publisher:
publish.yml on yz3440/gsv-ocr-check
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gsv_ocr_check-0.1.0.tar.gz -
Subject digest:
55e765e4ed6e1aa289d137dfb864757770ff96d83182d1680b2b2e17508a0edc - Sigstore transparency entry: 1054356589
- Sigstore integration time:
-
Permalink:
yz3440/gsv-ocr-check@7023721b546c2a0466e40a1ea94471810149a06c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yz3440
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7023721b546c2a0466e40a1ea94471810149a06c -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5cb44382c6539673c841521bc1150f2a33c1fe79601d363329e8b5385b83fcef
|
|
| MD5 |
ff344e86931279e7b9232d8d0c8ed73d
|
|
| BLAKE2b-256 |
dfed60ebba28a6cbcd386442e4ee6c0c46b6da2bcf581d6fbb4c9354c00abc03
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gsv_ocr_check-0.1.0-py3-none-any.whl -
Subject digest:
5cb44382c6539673c841521bc1150f2a33c1fe79601d363329e8b5385b83fcef - Sigstore transparency entry: 1054356628
- Sigstore integration time:
-
Permalink:
yz3440/gsv-ocr-check@7023721b546c2a0466e40a1ea94471810149a06c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/yz3440
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7023721b546c2a0466e40a1ea94471810149a06c -
Trigger Event:
release
-
Statement type: