Skip to content

Instantly share code, notes, and snippets.

@MarsTechHAN
Created January 9, 2022 23:37
Show Gist options
  • Save MarsTechHAN/24c7ad365733e5bde78fbae77854ccd6 to your computer and use it in GitHub Desktop.
Save MarsTechHAN/24c7ad365733e5bde78fbae77854ccd6 to your computer and use it in GitHub Desktop.
# Released under MIT License
# Credit to https://github.com/timy90022/Perspective-and-Equirectangular
import requests
import numpy as np
import cv2
# Expected output image resolution
equirec_img_shape = (1000, 2000, 3)
# W/H Ratio should only be 2:1
assert equirec_img_shape[1] / equirec_img_shape[0] == 2
# Location you want to capture
logtitude = 39.480336
latitude = -87.326027
# Google API limit the image shape to be 640x640, fov to be 120deg
gno_img_shape = 640
fov = np.ceil(360 * (gno_img_shape / np.max(equirec_img_shape))).astype(int)
if fov >= 120:
fov = 120
# Horizontal Overlay Factor
h_overlay_fac = 0.8
# Your google api key
key = "YOUR_GOOGLE_API_KEY"
def get_street_view_image(size, logtitude, latitude, fov, heading, pitch):
url = "https://maps.googleapis.com/maps/api/streetview?size={}&location={},{}&fov={}&heading={}&pitch={}&key={}".format(
size, logtitude, latitude, fov, heading, pitch, key)
resp = requests.get(url)
if resp.status_code == 200:
return resp.content
else:
print('Failed to retrieve image')
return None
def _main():
print('Start to capture street view image')
images = []
for heading in list(range(0, 360, int(fov*h_overlay_fac)))+[360]:
for pitch in list(range(fov//2-90, 90-fov//2, fov))+[90-fov//2]:
size = "%dx%d" % (gno_img_shape, gno_img_shape)
img = get_street_view_image(
size, logtitude, latitude, fov, heading, pitch)
if img:
img = np.frombuffer(img, np.uint8)
img = cv2.imdecode(img, cv2.IMREAD_COLOR)
cv2.imwrite('./image/%d_%d_captured.jpg' % (heading, pitch), img)
# img = cv2.imread('./image/%d_%d_captured.jpg' % (heading, pitch)) For debugging
print('Captured Heading: %d, Pitch: %d, Image Shape:' %
(heading, pitch), img.shape)
images.append({'img': img, 'heading': heading, 'pitch': pitch})
print('Start merging images')
equirec_img = np.zeros(equirec_img_shape, np.int32)
equirec_mask = np.zeros(equirec_img_shape, np.int32)
for image in images:
print('Processing image, Heading: %d, Pitch: %d' %
(image['heading'], image['pitch']))
x, y = np.meshgrid(np.linspace(-180, 180,
equirec_img_shape[1]), np.linspace(90, -90, equirec_img_shape[0]))
x_map = np.cos(np.radians(x)) * np.cos(np.radians(y))
y_map = np.sin(np.radians(x)) * np.cos(np.radians(y))
z_map = np.sin(np.radians(y))
xyz = np.stack((x_map, y_map, z_map), axis=2)
xyz = xyz.reshape([equirec_img_shape[1] * equirec_img_shape[0], 3]).T
y_axis = np.array([0.0, 1.0, 0.0], np.float32)
z_axis = np.array([0.0, 0.0, 1.0], np.float32)
[R1, _] = cv2.Rodrigues(z_axis * np.radians(image['heading']))
[R2, _] = cv2.Rodrigues(np.dot(R1, y_axis) *
np.radians(-image['pitch']))
R1 = np.linalg.inv(R1)
R2 = np.linalg.inv(R2)
xyz = np.dot(R2, xyz)
xyz = np.dot(R1, xyz).T
xyz = xyz.reshape([equirec_img_shape[0], equirec_img_shape[1], 3])
inverse_mask = np.where(xyz[:, :, 0] > 0, 1, 0)
xyz[:, :] = xyz[:, :] / \
np.repeat(xyz[:, :, 0][:, :, np.newaxis], 3, axis=2)
w_len = np.tan(np.radians(fov / 2.0))
h_len = np.tan(np.radians(fov / 2.0))
lon_map = np.where((-w_len < xyz[:, :, 1]) & (xyz[:, :, 1] < w_len) & (-h_len < xyz[:, :, 2])
& (xyz[:, :, 2] < h_len), (xyz[:, :, 1]+w_len)/2/w_len*gno_img_shape, 0)
lat_map = np.where((-w_len < xyz[:, :, 1]) & (xyz[:, :, 1] < w_len) & (-h_len < xyz[:, :, 2])
& (xyz[:, :, 2] < h_len), (-xyz[:, :, 2]+h_len)/2/h_len*gno_img_shape, 0)
mask = np.where((-w_len < xyz[:, :, 1]) & (xyz[:, :, 1] < w_len) & (-h_len < xyz[:, :, 2])
& (xyz[:, :, 2] < h_len), 1, 0)
persp = cv2.remap(image['img'], lon_map.astype(np.float32), lat_map.astype(
np.float32), cv2.INTER_CUBIC, borderMode=cv2.BORDER_WRAP)
mask = mask * inverse_mask
mask = np.repeat(mask[:, :, np.newaxis], 3, axis=2)
cv2.imwrite('./image/%d_%d_perp.jpg' %
(image['heading'], image['pitch']), persp)
cv2.imwrite('./image/%d_%d_mask.jpg' %
(image['heading'], image['pitch']), mask*255)
equirec_img += (persp * mask).astype(np.int32)
equirec_mask += mask
equirec_mask = np.where(equirec_mask == 0, 1, equirec_mask)
equirec_img = (np.divide(equirec_img, equirec_mask)).astype(np.uint8)
cv2.imwrite('panorama.jpg', equirec_img)
if __name__ == '__main__':
_main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment