Created
January 9, 2022 23:37
-
-
Save MarsTechHAN/24c7ad365733e5bde78fbae77854ccd6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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