Spaces:
Build error
Build error
""" | |
@date: 2021/6/30 | |
@description: | |
""" | |
import numpy as np | |
from typing import List | |
from utils.boundary import * | |
from scipy.optimize import least_squares | |
from functools import partial | |
def lsq_fit(ceil_norm, floor_norm): | |
""" | |
Least Squares | |
:param ceil_norm: | |
:param floor_norm: | |
:return: | |
""" | |
def error_fun(ratio, ceil_norm, floor_norm): | |
error = np.abs(ratio * ceil_norm - floor_norm) | |
return error | |
init_ratio = np.mean(floor_norm / ceil_norm, axis=-1) | |
error_func = partial(error_fun, ceil_norm=ceil_norm, floor_norm=floor_norm) | |
ret = least_squares(error_func, init_ratio, verbose=0) | |
ratio = ret.x[0] | |
return ratio | |
def mean_percentile_fit(ceil_norm, floor_norm, p1=25, p2=75): | |
""" | |
:param ceil_norm: | |
:param floor_norm: | |
:param p1: | |
:param p2: | |
:return: | |
""" | |
ratio = floor_norm / ceil_norm | |
r_min = np.percentile(ratio, p1) | |
r_max = np.percentile(ratio, p2) | |
return ratio[(r_min <= ratio) & (ratio <= r_max)].mean() | |
def calc_ceil_ratio(boundaries: List[np.array], mode='lsq'): | |
""" | |
:param boundaries: [ [[cu1, cv1], [cu2, cv2], ...], [[fu1, fv1], [fu2, fv2], ...] ] | |
:param mode: 'lsq' or 'mean' | |
:return: | |
""" | |
assert len(boundaries[0].shape) < 4 and len(boundaries[1].shape) < 4, 'error shape' | |
if not is_normal_layout(boundaries): | |
return 0 | |
ceil_boundary = boundaries[0] | |
floor_boundary = boundaries[1] | |
assert ceil_boundary.shape[-2] == floor_boundary.shape[-2], "boundary need same length" | |
ceil_xyz = uv2xyz(ceil_boundary, -1) | |
floor_xyz = uv2xyz(floor_boundary, 1) | |
ceil_xz = ceil_xyz[..., ::2] | |
floor_xz = floor_xyz[..., ::2] | |
ceil_norm = np.linalg.norm(ceil_xz, axis=-1) | |
floor_norm = np.linalg.norm(floor_xz, axis=-1) | |
if mode == "lsq": | |
if len(ceil_norm.shape) == 2: | |
ratio = np.array([lsq_fit(ceil_norm[i], floor_norm[i]) for i in range(ceil_norm.shape[0])]) | |
else: | |
ratio = lsq_fit(ceil_norm, floor_norm) | |
else: | |
if len(ceil_norm.shape) == 2: | |
ratio = np.array([mean_percentile_fit(ceil_norm[i], floor_norm[i]) for i in range(ceil_norm.shape[0])]) | |
else: | |
ratio = mean_percentile_fit(ceil_norm, floor_norm) | |
return ratio | |
def calc_ceil_height(boundaries: List[np.array], camera_height=1.6, mode='lsq') -> float: | |
""" | |
:param boundaries: [ [[cu1, cv1], [cu2, cv2], ...], [[fu1, fv1], [fu2, fv2], ...] ] | |
:param camera_height: | |
:param mode: | |
:return: | |
""" | |
ratio = calc_ceil_ratio(boundaries, mode) | |
ceil_height = camera_height * ratio | |
return ceil_height | |
def calc_room_height(boundaries: List[np.array], camera_height=1.6, mode='lsq') -> float: | |
""" | |
:param boundaries: also can corners,format: [ [[cu1, cv1], [cu2, cv2], ...], [[fu1, fv1], [fu2, fv2], ...] ], | |
0 denotes ceil, 1 denotes floor | |
:param camera_height: actual camera height determines the scale | |
:param mode: fitting method lsq or mean | |
:return: | |
""" | |
ceil_height = calc_ceil_height(boundaries, camera_height, mode) | |
room_height = camera_height + ceil_height | |
return room_height | |
def height2ratio(height, camera_height=1.6): | |
ceil_height = height - camera_height | |
ratio = ceil_height / camera_height | |
return ratio | |
def ratio2height(ratio, camera_height=1.6): | |
ceil_height = camera_height * ratio | |
room_height = camera_height + ceil_height | |
return room_height | |
if __name__ == '__main__': | |
from dataset.mp3d_dataset import MP3DDataset | |
dataset = MP3DDataset(root_dir="../src/dataset/mp3d", mode="train") | |
for data in dataset: | |
ceil_corners = data['corners'][::2] | |
floor_corners = data['corners'][1::2] | |
# ceil_boundary = corners2boundary(ceil_corners, length=1024) | |
# floor_boundary = corners2boundary(floor_corners, length=1024) | |
room_height1 = calc_room_height([ceil_corners, floor_corners], camera_height=1.6, mode='mean') | |
room_height2 = calc_room_height([ceil_corners, floor_corners], camera_height=1.6, mode='lsq') | |
print(room_height1, room_height2, data['cameraCeilingHeight'] + 1.6) | |