|
""" |
|
@Date: 2021/07/27 |
|
@description: |
|
""" |
|
import numpy as np |
|
import cv2 |
|
import functools |
|
|
|
from utils.conversion import pixel2lonlat, lonlat2pixel, uv2lonlat, lonlat2uv, pixel2uv |
|
|
|
|
|
@functools.lru_cache() |
|
def prepare_stretch(w, h): |
|
lon = pixel2lonlat(np.array(range(w)), w=w, axis=0) |
|
lat = pixel2lonlat(np.array(range(h)), h=h, axis=1) |
|
sin_lon = np.sin(lon) |
|
cos_lon = np.cos(lon) |
|
tan_lat = np.tan(lat) |
|
return sin_lon, cos_lon, tan_lat |
|
|
|
|
|
def pano_stretch_image(pano_img, kx, ky, kz): |
|
""" |
|
Note that this is the inverse mapping, which refers to Equation 3 in HorizonNet paper (the coordinate system in |
|
the paper is different from here, xz needs to be swapped) |
|
:param pano_img: a panorama image, shape must be [h,w,c] |
|
:param kx: stretching along left-right direction |
|
:param ky: stretching along up-down direction |
|
:param kz: stretching along front-back direction |
|
:return: |
|
""" |
|
w = pano_img.shape[1] |
|
h = pano_img.shape[0] |
|
|
|
sin_lon, cos_lon, tan_lat = prepare_stretch(w, h) |
|
|
|
n_lon = np.arctan2(sin_lon * kz / kx, cos_lon) |
|
n_lat = np.arctan(tan_lat[..., None] * np.sin(n_lon) / sin_lon * kx / ky) |
|
n_pu = lonlat2pixel(n_lon, w=w, axis=0, need_round=False) |
|
n_pv = lonlat2pixel(n_lat, h=h, axis=1, need_round=False) |
|
|
|
pixel_map = np.empty((h, w, 2), dtype=np.float32) |
|
pixel_map[..., 0] = n_pu |
|
pixel_map[..., 1] = n_pv |
|
map1 = pixel_map[..., 0] |
|
map2 = pixel_map[..., 1] |
|
|
|
new_img = cv2.remap(pano_img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_WRAP) |
|
return new_img |
|
|
|
|
|
def pano_stretch_conner(corners, kx, ky, kz): |
|
""" |
|
:param corners: |
|
:param kx: stretching along left-right direction |
|
:param ky: stretching along up-down direction |
|
:param kz: stretching along front-back direction |
|
:return: |
|
""" |
|
|
|
lonlat = uv2lonlat(corners) |
|
sin_lon = np.sin(lonlat[..., 0:1]) |
|
cos_lon = np.cos(lonlat[..., 0:1]) |
|
tan_lat = np.tan(lonlat[..., 1:2]) |
|
|
|
n_lon = np.arctan2(sin_lon * kx / kz, cos_lon) |
|
|
|
a = np.bitwise_or(corners[..., 0] == 0.5, corners[..., 0] == 1) |
|
b = np.bitwise_not(a) |
|
w = np.zeros_like(n_lon) |
|
w[b] = np.sin(n_lon[b]) / sin_lon[b] |
|
w[a] = kx / kz |
|
|
|
n_lat = np.arctan(tan_lat * w / kx * ky) |
|
|
|
lst = [n_lon, n_lat] |
|
lonlat = np.concatenate(lst, axis=-1) |
|
new_corners = lonlat2uv(lonlat) |
|
return new_corners |
|
|
|
|
|
def pano_stretch(pano_img, corners, kx, ky, kz): |
|
""" |
|
:param pano_img: a panorama image, shape must be [h,w,c] |
|
:param corners: |
|
:param kx: stretching along left-right direction |
|
:param ky: stretching along up-down direction |
|
:param kz: stretching along front-back direction |
|
:return: |
|
""" |
|
new_img = pano_stretch_image(pano_img, kx, ky, kz) |
|
new_corners = pano_stretch_conner(corners, kx, ky, kz) |
|
return new_img, new_corners |
|
|
|
|
|
class PanoDataAugmentation: |
|
def __init__(self, aug): |
|
self.aug = aug |
|
self.parameters = {} |
|
|
|
def need_aug(self, name): |
|
return name in self.aug and self.aug[name] |
|
|
|
def execute_space_aug(self, corners, image): |
|
if image is None: |
|
return image |
|
|
|
if self.aug is None: |
|
return corners, image |
|
w = image.shape[1] |
|
h = image.shape[0] |
|
|
|
if self.need_aug('STRETCH'): |
|
kx = np.random.uniform(1, 2) |
|
kx = 1 / kx if np.random.randint(2) == 0 else kx |
|
|
|
|
|
|
|
ky = 1 |
|
kz = np.random.uniform(1, 2) |
|
kz = 1 / kz if np.random.randint(2) == 0 else kz |
|
image, corners = pano_stretch(image, corners, kx, ky, kz) |
|
self.parameters['STRETCH'] = {'kx': kx, 'ky': ky, 'kz': kz} |
|
else: |
|
self.parameters['STRETCH'] = None |
|
|
|
if self.need_aug('ROTATE'): |
|
d_pu = np.random.randint(w) |
|
image = np.roll(image, d_pu, axis=1) |
|
corners[..., 0] = (corners[..., 0] + pixel2uv(np.array([d_pu]), w, h)) % pixel2uv(np.array([w]), w, h) |
|
self.parameters['ROTATE'] = d_pu |
|
else: |
|
self.parameters['ROTATE'] = None |
|
|
|
if self.need_aug('FLIP') and np.random.randint(2) == 0: |
|
image = np.flip(image, axis=1).copy() |
|
corners[..., 0] = pixel2uv(np.array([w]), w, h) - corners[..., 0] |
|
corners = corners[::-1] |
|
self.parameters['FLIP'] = True |
|
else: |
|
self.parameters['FLIP'] = None |
|
|
|
return corners, image |
|
|
|
def execute_visual_aug(self, image): |
|
if self.need_aug('GAMMA'): |
|
p = np.random.uniform(1, 2) |
|
if np.random.randint(2) == 0: |
|
p = 1 / p |
|
image = image ** p |
|
self.parameters['GAMMA'] = p |
|
else: |
|
self.parameters['GAMMA'] = None |
|
|
|
|
|
if self.need_aug('HUE') or self.need_aug('SATURATION'): |
|
image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) |
|
|
|
if self.need_aug('HUE') and np.random.randint(2) == 0: |
|
p = np.random.uniform(-0.1, 0.1) |
|
image[..., 0] = np.mod(image[..., 0] + p * 180, 180) |
|
self.parameters['HUE'] = p |
|
else: |
|
self.parameters['HUE'] = None |
|
|
|
if self.need_aug('SATURATION') and np.random.randint(2) == 0: |
|
p = np.random.uniform(0.5, 1.5) |
|
image[..., 1] = np.clip(image[..., 1] * p, 0, 1) |
|
self.parameters['SATURATION'] = p |
|
else: |
|
self.parameters['SATURATION'] = None |
|
|
|
image = cv2.cvtColor(image, cv2.COLOR_HSV2RGB) |
|
|
|
if self.need_aug('CONTRAST') and np.random.randint(2) == 0: |
|
p = np.random.uniform(0.9, 1.1) |
|
mean = image.mean(axis=0).mean(axis=0) |
|
image = (image - mean) * p + mean |
|
image = np.clip(image, 0, 1) |
|
self.parameters['CONTRAST'] = p |
|
else: |
|
self.parameters['CONTRAST'] = None |
|
|
|
return image |
|
|
|
def execute_aug(self, corners, image): |
|
corners, image = self.execute_space_aug(corners, image) |
|
if image is not None: |
|
image = self.execute_visual_aug(image) |
|
return corners, image |
|
|
|
|
|
if __name__ == '__main__1': |
|
from tqdm import trange |
|
from visualization.floorplan import draw_floorplan |
|
from dataset.communal.read import read_image, read_label |
|
from utils.time_watch import TimeWatch |
|
from utils.conversion import uv2xyz |
|
from utils.boundary import corners2boundary |
|
|
|
np.random.seed(123) |
|
pano_img_path = "../../src/dataset/mp3d/image/TbHJrupSAjP_f320ae084f3a447da3e8ab11dd5f9320.png" |
|
label_path = "../../src/dataset/mp3d/label/TbHJrupSAjP_f320ae084f3a447da3e8ab11dd5f9320.json" |
|
pano_img = read_image(pano_img_path) |
|
label = read_label(label_path) |
|
|
|
corners = label['corners'] |
|
ratio = label['ratio'] |
|
|
|
pano_aug = PanoDataAugmentation(aug={ |
|
'STRETCH': True, |
|
'ROTATE': True, |
|
'FLIP': True, |
|
'GAMMA': True, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
w = TimeWatch("test") |
|
for i in trange(50000): |
|
new_corners, new_pano_img = pano_aug.execute_aug(corners.copy(), pano_img.copy()) |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
from utils.boundary import corners2boundary |
|
from visualization.floorplan import draw_floorplan |
|
from utils.boundary import visibility_corners |
|
|
|
corners = np.array([[0.7664539, 0.7416811], |
|
[0.06641078, 0.6521386], |
|
[0.30997428, 0.57855356], |
|
[0.383300784, 0.58726823], |
|
[0.383300775, 0.8005296], |
|
[0.5062902, 0.74822706]]) |
|
corners = visibility_corners(corners) |
|
print(corners) |
|
|
|
|
|
visible_floor_boundary = corners2boundary(corners, length=256, visible=True) |
|
|
|
print(len(visible_floor_boundary)) |
|
|
|
|
|
if __name__ == '__main__0': |
|
from visualization.floorplan import draw_floorplan |
|
|
|
from dataset.communal.read import read_image, read_label |
|
from utils.time_watch import TimeWatch |
|
from utils.conversion import uv2xyz |
|
|
|
|
|
pano_img_path = "../../src/dataset/mp3d/image/VVfe2KiqLaN_35b41dcbfcf84f96878f6ca28c70e5af.png" |
|
label_path = "../../src/dataset/mp3d/label/VVfe2KiqLaN_35b41dcbfcf84f96878f6ca28c70e5af.json" |
|
pano_img = read_image(pano_img_path) |
|
label = read_label(label_path) |
|
|
|
corners = label['corners'] |
|
ratio = label['ratio'] |
|
|
|
|
|
|
|
w = TimeWatch() |
|
for i in range(5): |
|
kx = np.random.uniform(1, 2) |
|
kx = 1 / kx if np.random.randint(2) == 0 else kx |
|
ky = np.random.uniform(1, 2) |
|
ky = 1 / ky if np.random.randint(2) == 0 else ky |
|
kz = np.random.uniform(1, 2) |
|
kz = 1 / kz if np.random.randint(2) == 0 else kz |
|
new_corners = pano_stretch_conner(corners.copy(), kx, ky, kz) |
|
draw_floorplan(uv2xyz(new_corners, plan_y=1.6)[..., ::2], show=True, marker_color=0.5, center_color=0.8, |
|
show_radius=8) |
|
|