简介
上篇博客室内场景重建二 立方体拟合中, 介绍了如何在粗略平面估计的基础上, 做精细化的处理, 最终得到了室内场景的6个非常精细的平面估计, 以及这个场景的一些测绘数据.
本篇将在上篇的结果的基础上, 将原始的panasonic_0.1_n.ply
中的点分成三类:
- 室外的点, 即噪点
- 在室内, 且在平面上的点, 即在6个墙面上的点
- 在室内, 但不在平面上的点, 即室内人和物的点.
实现思路
分割噪点
理论思路
已知由6个平面确定的立方体
V
=
[
P
b
u
t
t
o
n
,
P
t
o
p
,
P
b
a
c
k
,
P
f
r
o
n
t
,
P
l
e
f
t
,
P
r
i
g
h
t
]
,
P
i
=
[
A
i
,
B
i
,
C
i
,
−
1
]
V=[P_{button}, P_{top}, P_{back}, P_{front}, P_{left}, P_{right}], P_i =[A_i, B_i, C_i, -1]
V=[Pbutton,Ptop,Pback,Pfront,Pleft,Pright],Pi=[Ai,Bi,Ci,−1], 且已知这个立方体的长宽高为
l
e
n
g
t
h
,
w
i
d
t
h
,
h
e
i
g
h
t
length, width, height
length,width,height, 已知点
P
o
i
n
t
=
[
x
,
y
,
z
]
Point=[x, y, z]
Point=[x,y,z], 可以求得如下的六个距离:
d
i
s
b
u
t
t
o
n
=
d
i
s
t
a
n
c
e
_
p
o
i
n
t
_
t
o
_
p
l
a
n
e
(
P
o
i
n
t
,
P
l
a
n
e
b
u
t
t
o
n
)
d
i
s
t
o
p
=
d
i
s
t
a
n
c
e
_
p
o
i
n
t
_
t
o
_
p
l
a
n
e
(
P
o
i
n
t
,
P
l
a
n
e
t
o
p
)
d
i
s
b
a
c
k
=
d
i
s
t
a
n
c
e
_
p
o
i
n
t
_
t
o
_
p
l
a
n
e
(
P
o
i
n
t
,
P
l
a
n
e
b
a
c
k
)
d
i
s
f
r
o
n
t
=
d
i
s
t
a
n
c
e
_
p
o
i
n
t
_
t
o
_
p
l
a
n
e
(
P
o
i
n
t
,
P
l
a
n
e
f
r
o
n
t
)
d
i
s
l
e
f
t
=
d
i
s
t
a
n
c
e
_
p
o
i
n
t
_
t
o
_
p
l
a
n
e
(
P
o
i
n
t
,
P
l
a
n
e
l
e
f
t
)
d
i
s
r
i
g
h
t
=
d
i
s
t
a
n
c
e
_
p
o
i
n
t
_
t
o
_
p
l
a
n
e
(
P
o
i
n
t
,
P
l
a
n
e
r
i
g
h
t
)
dis_{button} = distance\_point\_to\_plane(Point, Plane_{button}) \\ dis_{top} = distance\_point\_to\_plane(Point, Plane_{top}) \\ dis_{back} = distance\_point\_to\_plane(Point, Plane_{back}) \\ dis_{front} = distance\_point\_to\_plane(Point, Plane_{front}) \\ dis_{left} = distance\_point\_to\_plane(Point, Plane_{left}) \\ dis_{right} = distance\_point\_to\_plane(Point, Plane_{right}) \\
disbutton=distance_point_to_plane(Point,Planebutton)distop=distance_point_to_plane(Point,Planetop)disback=distance_point_to_plane(Point,Planeback)disfront=distance_point_to_plane(Point,Planefront)disleft=distance_point_to_plane(Point,Planeleft)disright=distance_point_to_plane(Point,Planeright)
取:
d
i
s
_
m
a
x
0
=
m
a
x
(
d
i
s
b
u
t
t
o
n
,
d
i
s
t
o
p
)
d
i
s
_
m
a
x
1
=
m
a
x
(
d
i
s
b
a
c
k
,
d
i
s
f
r
o
n
t
)
d
i
s
_
m
a
x
2
=
m
a
x
(
d
i
s
l
e
f
t
,
d
i
s
r
i
g
h
t
)
dis\_max_0 = max(dis_{button}, dis_{top}) \\ dis\_max_1 = max(dis_{back}, dis_{front}) \\ dis\_max_2 = max(dis_{left}, dis_{right}) \\
dis_max0=max(disbutton,distop)dis_max1=max(disback,disfront)dis_max2=max(disleft,disright)
那么, 只要这个点在室外, 下面的语句_值必为True
:
(
d
i
s
_
m
a
x
0
>
h
e
i
g
h
t
)
∣
∣
(
d
i
s
_
m
a
x
1
>
w
i
d
t
h
)
∣
∣
(
d
i
s
_
m
a
x
2
>
l
e
n
g
t
h
)
(dis\_max_0>height) \ || \ (dis\_max_1>width) \ || \ (dis\_max_2>length)
(dis_max0>height) ∣∣ (dis_max1>width) ∣∣ (dis_max2>length)
考虑到一些误差, 这里可以加上一个阈值, 变成:
(
d
i
s
_
m
a
x
0
>
h
e
i
g
h
t
+
ϵ
)
∣
∣
(
d
i
s
_
m
a
x
1
>
w
i
d
t
h
+
ϵ
)
∣
∣
(
d
i
s
_
m
a
x
2
>
l
e
n
g
t
h
+
ϵ
)
(dis\_max_0>height+\epsilon) \ || \ (dis\_max_1>width+\epsilon) \ || \ (dis\_max_2>length+\epsilon)
(dis_max0>height+ϵ) ∣∣ (dis_max1>width+ϵ) ∣∣ (dis_max2>length+ϵ)
编程实现
def sample_condition_points_outside_planes(points, planes, cube):
"""
从points中, 挑选出在立方体外面的点, 返回一个sample_condition
根据点到对应两个面的距离来判断, 如果有一个距离大于立方体的一个长度度量, 则认为这个点在立方体外面
@param points:
@param planes: [下, 上, 后, 前, 左, 右] 0,1 2,3 4,5
@param cube: [高度, 宽度, 长度] 0, 1, 2
@return: np.ndarray, dtype=bool
"""
if not type(points) == np.array:
points = np.array(points)
if not type(planes) == np.array:
planes = np.array(planes)
if not type(cube) == np.array:
cube = np.array(cube)
sample_condition = np.zeros(shape=(points.shape[0],), dtype=np.bool) # 假设所有的点都在立方体内
for i, point in enumerate(points):
for j in range(cube.shape[0]):
plane_1, plane_2 = planes[2 * j], planes[2 * j + 1]
length = cube[j]
dis_1 = distance_point_to_plane(point, plane_1)
dis_2 = distance_point_to_plane(point, plane_2)
# 该点某个坐标不在立方体内, 跳过剩余判断
if (dis_1 > length+2*POINT_PLANE_DIS_THRESHOLD) or (dis_2 > length+2*POINT_PLANE_DIS_THRESHOLD):
sample_condition[i] = True
return sample_condition
分割室内点
理论思路
去掉了上面的点, 那么剩下来的点就都是室内的点了, 而具体分割这个点属于某个墙面, 还是属于某个物体, 采用的方法依然是基于点到直线的距离的.
依然取上面介绍的6个距离 d i s b u t t o n , d i s t o p , d i s b a c k , d i s f r o n t , d i s l e f t , d i s r i g h t dis_{button}, dis_{top}, dis_{back}, dis_{front}, dis_{left}, dis_{right} disbutton,distop,disback,disfront,disleft,disright, 只要某个 d i s < ϵ dis<\epsilon dis<ϵ, 则认为这个点在这个平面上
那么去除在平面上的点, 剩下来的就是既不在室外, 也不在平面上的点, 也就是室内人和物的点.
编程实现
def sample_condition_points_off_planes(points, planes):
"""
从points中, 挑选出离planes特别远的点, 返回一个sample_condition
@param points:
@param planes:
@return: np.ndarray
"""
if not type(points) == np.array:
points = np.array(points)
if not type(planes) == np.array:
planes = np.array(planes)
sample_condition = np.ones(shape=(points.shape[0],), dtype=np.bool) # 假设所有点都不在平面上
for idx, point in enumerate(points):
for plane in planes:
dis = distance_point_to_plane(point, plane)
if dis < POINT_PLANE_DIS_THRESHOLD: # 该点在某一平面上, 跳过判断剩余的平面
sample_condition[idx] = False
break
return sample_condition
结果
将分割结果写入.obj
和mtl
后, 显示如下图:
其中从左到右, 从上到下分别是室内人和物的点, 6个墙面上的点, 室外噪点, 6个墙面