BilalSardar commited on
Commit
98b2032
·
verified ·
1 Parent(s): 596d5d2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -1
app.py CHANGED
@@ -13,7 +13,149 @@ import asyncio
13
  import aiohttp
14
  import io
15
 
16
- # [Previous StreetViewDownloader class remains the same]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  def process_street_view(url, zoom, cols, rows, progress=gr.Progress()):
19
  """Process the Street View URL with custom parameters."""
 
13
  import aiohttp
14
  import io
15
 
16
+ import gradio as gr
17
+ from PIL import Image
18
+ import tempfile
19
+ import os
20
+ from pathlib import Path
21
+ import shutil
22
+ import base64
23
+ import requests
24
+ import re
25
+ import time
26
+ from PIL import ImageEnhance
27
+ import concurrent.futures
28
+ import asyncio
29
+ import aiohttp
30
+ import io
31
+
32
+ class StreetViewDownloader:
33
+ def __init__(self):
34
+ self.headers = {
35
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
36
+ }
37
+ # Using a smaller session for better connection reuse
38
+ self.session = requests.Session()
39
+
40
+ def extract_panoid(self, url):
41
+ """Extract panorama ID from Google Maps URL."""
42
+ pattern = r'!1s([A-Za-z0-9-_]+)!'
43
+ match = re.search(pattern, url)
44
+ if match:
45
+ return match.group(1)
46
+ raise ValueError("Could not find panorama ID in URL")
47
+
48
+ async def download_tile_async(self, session, panoid, x, y, adjusted_y, zoom, output_dir):
49
+ """Download a single tile asynchronously."""
50
+ tile_url = f"https://streetviewpixels-pa.googleapis.com/v1/tile?cb_client=maps_sv.tactile&panoid={panoid}&x={x}&y={adjusted_y}&zoom={zoom}"
51
+ output_file = Path(output_dir) / f"tile_{x}_{y}.jpg"
52
+
53
+ try:
54
+ async with session.get(tile_url, headers=self.headers) as response:
55
+ if response.status == 200:
56
+ content = await response.read()
57
+ if len(content) > 1000:
58
+ output_file.write_bytes(content)
59
+ return (x, y)
60
+ except Exception as e:
61
+ print(f"Error downloading tile {x},{y}: {str(e)}")
62
+ return None
63
+
64
+ async def download_tiles_async(self, panoid, output_dir):
65
+ """Download tiles asynchronously with reduced resolution."""
66
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
67
+
68
+ # Reduced parameters for faster download
69
+ zoom = 2 # Reduced zoom level (less detail but faster)
70
+ cols = 16 # Reduced number of horizontal tiles
71
+ rows = 8 # Reduced number of vertical tiles
72
+ vertical_offset = 2 # Adjusted for the new grid
73
+
74
+ print(f"Downloading {cols * rows} tiles for panorama...")
75
+
76
+ async with aiohttp.ClientSession() as session:
77
+ tasks = []
78
+ for x in range(cols):
79
+ for y in range(rows):
80
+ adjusted_y = y - (rows // 2) + vertical_offset
81
+ task = self.download_tile_async(session, panoid, x, y, adjusted_y, zoom, output_dir)
82
+ tasks.append(task)
83
+
84
+ downloaded_tiles = []
85
+ for result in await asyncio.gather(*tasks):
86
+ if result:
87
+ downloaded_tiles.append(result)
88
+
89
+ return cols, rows, downloaded_tiles
90
+
91
+ def download_tiles(self, panoid, output_dir):
92
+ """Synchronous wrapper for async download."""
93
+ return asyncio.run(self.download_tiles_async(panoid, output_dir))
94
+
95
+ def create_360_panorama(self, directory, cols, rows, downloaded_tiles, output_file):
96
+ """Create an equirectangular 360° panorama from tiles with optimized processing."""
97
+ directory = Path(directory)
98
+
99
+ # Find a valid tile to get dimensions
100
+ valid_tile = None
101
+ for x, y in downloaded_tiles:
102
+ tile_path = directory / f"tile_{x}_{y}.jpg"
103
+ if tile_path.exists():
104
+ valid_tile = Image.open(tile_path)
105
+ break
106
+
107
+ if not valid_tile:
108
+ raise Exception("No valid tiles found in directory")
109
+
110
+ tile_width, tile_height = valid_tile.size
111
+ valid_tile.close()
112
+
113
+ # Create the panorama at optimized resolution
114
+ panorama_width = tile_width * cols
115
+ panorama_height = tile_height * rows
116
+
117
+ # Use RGB mode directly for better performance
118
+ panorama = Image.new('RGB', (panorama_width, panorama_height))
119
+
120
+ # Process tiles in parallel
121
+ def process_tile(tile_info):
122
+ x, y = tile_info
123
+ tile_path = directory / f"tile_{x}_{y}.jpg"
124
+ if tile_path.exists():
125
+ with Image.open(tile_path) as tile:
126
+ if tile.getbbox():
127
+ return (x * tile_width, y * tile_height, tile.copy())
128
+ return None
129
+
130
+ # Use ThreadPoolExecutor for parallel processing
131
+ with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
132
+ tile_results = list(executor.map(process_tile, downloaded_tiles))
133
+
134
+ # Paste all valid tiles
135
+ for result in tile_results:
136
+ if result:
137
+ x, y, tile = result
138
+ panorama.paste(tile, (x, y))
139
+ tile.close()
140
+
141
+ # Crop out any remaining black regions
142
+ bbox = panorama.getbbox()
143
+ if bbox:
144
+ panorama = panorama.crop(bbox)
145
+
146
+ # Quick enhancement
147
+ panorama = self.enhance_panorama(panorama)
148
+
149
+ # Save with optimized settings
150
+ panorama.save(output_file, 'JPEG', quality=95, optimize=True)
151
+ return output_file
152
+
153
+ def enhance_panorama(self, panorama):
154
+ """Quick enhancement with minimal processing."""
155
+ enhancer = ImageEnhance.Contrast(panorama)
156
+ panorama = enhancer.enhance(1.1)
157
+ return panorama
158
+
159
 
160
  def process_street_view(url, zoom, cols, rows, progress=gr.Progress()):
161
  """Process the Street View URL with custom parameters."""