File size: 4,150 Bytes
88b0dcb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
"""
@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)
|