mdanish commited on
Commit
e4503c7
·
1 Parent(s): d80eabe

attempt pano image cropping

Browse files
Files changed (2) hide show
  1. app.py +130 -15
  2. requirements.txt +3 -0
app.py CHANGED
@@ -1,4 +1,6 @@
1
  import streamlit as st
 
 
2
  import folium
3
  from streamlit_folium import st_folium
4
  import requests
@@ -32,6 +34,117 @@ if not MAPILLARY_ACCESS_TOKEN:
32
  st.error("Mapillary access token not found. Please configure it in the Space secrets.")
33
  st.stop()
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  def get_bounding_box(lat, lon):
36
  """
37
  Create a bounding box around a point that extends roughly 25 meters in each direction
@@ -54,9 +167,8 @@ def get_nearest_image(lat, lon):
54
  """
55
  bbox = get_bounding_box(lat, lon)
56
  params = {
57
- 'fields': 'id,thumb_1024_url',
58
  'limit': 1,
59
- 'is_pano': False,
60
  'bbox': f'{bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]}'
61
  }
62
 
@@ -69,11 +181,11 @@ def get_nearest_image(lat, lon):
69
  )
70
  response.raise_for_status()
71
  data = response.json()
72
-
73
  if 'data' in data and len(data['data']) > 0:
74
  return data['data'][0]
75
  return None
76
-
77
  except requests.exceptions.RequestException as e:
78
  st.error(f"Error fetching Mapillary data: {str(e)}")
79
  return None
@@ -132,7 +244,7 @@ def load_knn():
132
 
133
  def main():
134
  st.title("Percept: Map Explorer")
135
-
136
  try:
137
  with st.spinner('Loading CLIP model... This may take a moment.'):
138
  model, preprocess, tokenizer = load_model()
@@ -148,35 +260,38 @@ def main():
148
  # Initialize the map centered on Amsterdam
149
  amsterdam_coords = [52.3676, 4.9041]
150
  m = folium.Map(location=amsterdam_coords, zoom_start=13)
151
-
152
  # Add a marker for Amsterdam city center
153
  folium.Marker(
154
  amsterdam_coords,
155
  popup="Amsterdam City Center",
156
  icon=folium.Icon(color="red", icon="info-sign")
157
  ).add_to(m)
158
-
159
  # Display the map and get clicked coordinates
160
  map_data = st_folium(m, height=400, width=700)
161
-
162
  # Check if a location was clicked
163
  if map_data['last_clicked']:
164
  lat = map_data['last_clicked']['lat']
165
  lng = map_data['last_clicked']['lng']
166
-
167
  st.write(f"Selected coordinates: {lat:.4f}, {lng:.4f}")
168
-
169
  # Get nearest Mapillary image
170
  with st.spinner('Fetching street view image...'):
171
  image_data = get_nearest_image(lat, lng)
172
-
173
  if image_data:
174
  # Display the image
175
  try:
176
- response = requests.get(image_data['thumb_1024_url'])
177
- image = Image.open(BytesIO(response.content))
 
 
 
178
  st.image(image, caption="Street View", width=400)
179
-
180
  # Add download button
181
  st.download_button(
182
  label="Download Image",
@@ -201,7 +316,7 @@ def main():
201
  k = 40
202
  for cat in categories:
203
  st.write(cat, f'rating = {knn_get_score(knn, k, cat, vec):.1f}')
204
-
205
  except Exception as e:
206
  st.error(f"Error displaying image: {str(e)}")
207
  else:
 
1
  import streamlit as st
2
+ import cv2
3
+ from ultralytics import YOLO # For street detection
4
  import folium
5
  from streamlit_folium import st_folium
6
  import requests
 
34
  st.error("Mapillary access token not found. Please configure it in the Space secrets.")
35
  st.stop()
36
 
37
+ def detect_and_crop_street(panorama_url, use_yolo=True):
38
+ """
39
+ Detect streets in a panoramic image and return a cropped normal-sized image
40
+ Args:
41
+ panorama_url: URL of the panoramic image
42
+ use_yolo: Whether to use YOLOv8 (True) or simple edge detection (False)
43
+ Returns:
44
+ cropped_image: PIL Image containing the cropped street view
45
+ """
46
+ # Download and convert image to CV2 format
47
+ response = requests.get(panorama_url)
48
+ img = Image.open(BytesIO(response.content))
49
+ cv_img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
50
+
51
+ if use_yolo:
52
+ # Load YOLOv8 model
53
+ model = YOLO('yolov8n.pt')
54
+
55
+ # Detect objects
56
+ results = model(cv_img)
57
+
58
+ # Look for road/street class (index 0 in COCO dataset)
59
+ street_boxes = []
60
+ for result in results:
61
+ for box, cls in zip(result.boxes.xyxy, result.boxes.cls):
62
+ if cls == 0: # road class
63
+ street_boxes.append(box.cpu().numpy())
64
+
65
+ if street_boxes:
66
+ # Take the largest street detection
67
+ largest_box = max(street_boxes, key=lambda box: (box[2]-box[0])*(box[3]-box[1]))
68
+ x1, y1, x2, y2 = map(int, largest_box)
69
+
70
+ # Add some padding
71
+ padding = 50
72
+ height, width = cv_img.shape[:2]
73
+ x1 = max(0, x1 - padding)
74
+ y1 = max(0, y1 - padding)
75
+ x2 = min(width, x2 + padding)
76
+ y2 = min(height, y2 + padding)
77
+
78
+ cropped = cv_img[y1:y2, x1:x2]
79
+ else:
80
+ # Fallback to edge detection if no streets found
81
+ cropped = edge_based_crop(cv_img)
82
+ else:
83
+ cropped = edge_based_crop(cv_img)
84
+
85
+ # Convert back to PIL Image
86
+ cropped_pil = Image.fromarray(cv2.cvtColor(cropped, cv2.COLOR_BGR2RGB))
87
+
88
+ # Resize to standard dimensions while maintaining aspect ratio
89
+ target_width = 1024
90
+ aspect_ratio = cropped.shape[1] / cropped.shape[0]
91
+ target_height = int(target_width / aspect_ratio)
92
+ cropped_pil = cropped_pil.resize((target_width, target_height), Image.Resampling.LANCZOS)
93
+
94
+ return cropped_pil
95
+
96
+ def edge_based_crop(cv_img):
97
+ """
98
+ Use edge detection to find and crop around street areas
99
+ """
100
+ # Convert to grayscale
101
+ gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
102
+
103
+ # Apply Gaussian blur
104
+ blurred = cv2.GaussianBlur(gray, (5, 5), 0)
105
+
106
+ # Detect edges
107
+ edges = cv2.Canny(blurred, 50, 150)
108
+
109
+ # Find contours
110
+ contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
111
+
112
+ if contours:
113
+ # Find the largest contour
114
+ largest_contour = max(contours, key=cv2.contourArea)
115
+ x, y, w, h = cv2.boundingRect(largest_contour)
116
+
117
+ # Add padding
118
+ padding = 50
119
+ height, width = cv_img.shape[:2]
120
+ x = max(0, x - padding)
121
+ y = max(0, y - padding)
122
+ w = min(width - x, w + 2*padding)
123
+ h = min(height - y, h + 2*padding)
124
+
125
+ return cv_img[y:y+h, x:x+w]
126
+ else:
127
+ # If no contours found, return center crop
128
+ height, width = cv_img.shape[:2]
129
+ center_x = width // 2
130
+ center_y = height // 2
131
+ crop_width = width // 3
132
+ crop_height = height // 3
133
+ return cv_img[center_y-crop_height//2:center_y+crop_height//2,
134
+ center_x-crop_width//2:center_x+crop_width//2]
135
+
136
+ # Example usage in your Streamlit app:
137
+ def process_panorama(panorama_url):
138
+ """
139
+ Process a panoramic image to get a street-centered crop
140
+ """
141
+ try:
142
+ cropped_image = detect_and_crop_street(panorama_url)
143
+ return cropped_image
144
+ except Exception as e:
145
+ st.error(f"Error processing panorama: {str(e)}")
146
+ return None
147
+
148
  def get_bounding_box(lat, lon):
149
  """
150
  Create a bounding box around a point that extends roughly 25 meters in each direction
 
167
  """
168
  bbox = get_bounding_box(lat, lon)
169
  params = {
170
+ 'fields': 'id,thumb_1024_url,is_pano',
171
  'limit': 1,
 
172
  'bbox': f'{bbox[0]},{bbox[1]},{bbox[2]},{bbox[3]}'
173
  }
174
 
 
181
  )
182
  response.raise_for_status()
183
  data = response.json()
184
+
185
  if 'data' in data and len(data['data']) > 0:
186
  return data['data'][0]
187
  return None
188
+
189
  except requests.exceptions.RequestException as e:
190
  st.error(f"Error fetching Mapillary data: {str(e)}")
191
  return None
 
244
 
245
  def main():
246
  st.title("Percept: Map Explorer")
247
+
248
  try:
249
  with st.spinner('Loading CLIP model... This may take a moment.'):
250
  model, preprocess, tokenizer = load_model()
 
260
  # Initialize the map centered on Amsterdam
261
  amsterdam_coords = [52.3676, 4.9041]
262
  m = folium.Map(location=amsterdam_coords, zoom_start=13)
263
+
264
  # Add a marker for Amsterdam city center
265
  folium.Marker(
266
  amsterdam_coords,
267
  popup="Amsterdam City Center",
268
  icon=folium.Icon(color="red", icon="info-sign")
269
  ).add_to(m)
270
+
271
  # Display the map and get clicked coordinates
272
  map_data = st_folium(m, height=400, width=700)
273
+
274
  # Check if a location was clicked
275
  if map_data['last_clicked']:
276
  lat = map_data['last_clicked']['lat']
277
  lng = map_data['last_clicked']['lng']
278
+
279
  st.write(f"Selected coordinates: {lat:.4f}, {lng:.4f}")
280
+
281
  # Get nearest Mapillary image
282
  with st.spinner('Fetching street view image...'):
283
  image_data = get_nearest_image(lat, lng)
284
+
285
  if image_data:
286
  # Display the image
287
  try:
288
+ if image_data['is_pano']:
289
+ image = process_panorama(image_data['thumb_1024_url'])
290
+ else:
291
+ response = requests.get(image_data['thumb_1024_url'])
292
+ image = Image.open(BytesIO(response.content))
293
  st.image(image, caption="Street View", width=400)
294
+
295
  # Add download button
296
  st.download_button(
297
  label="Download Image",
 
316
  k = 40
317
  for cat in categories:
318
  st.write(cat, f'rating = {knn_get_score(knn, k, cat, vec):.1f}')
319
+
320
  except Exception as e:
321
  st.error(f"Error displaying image: {str(e)}")
322
  else:
requirements.txt CHANGED
@@ -5,3 +5,6 @@ Pillow
5
  requests
6
  open_clip_torch
7
  scikit-learn
 
 
 
 
5
  requests
6
  open_clip_torch
7
  scikit-learn
8
+ opencv-python-headless
9
+ ultralytics
10
+ numpy