@ -4,8 +4,7 @@ import os
@@ -4,8 +4,7 @@ import os
import numpy as np
from scipy . spatial . transform import Rotation
import sys
# sys.path.append("/home/algo/Documents/openMVS/openMVS/libs/MVS/utils")
sys . path . append ( " /root/code/openMVS/libs/MVS/utils " )
sys . path . append ( " /home/algo/Documents/openMVS/openMVS/libs/MVS/utils " )
from colmap_loader import read_cameras_text , read_images_text , read_int_text , write_int_text , read_indices_from_file
# from get_pose_matrix import get_w2c
import argparse
@ -34,7 +33,6 @@ from typing import Dict, List, Set
@@ -34,7 +33,6 @@ from typing import Dict, List, Set
import struct
import math
# import os
from pathlib import Path
CameraModel = collections . namedtuple (
" CameraModel " , [ " model_id " , " model_name " , " num_params " ]
@ -1352,90 +1350,14 @@ class ModelProcessor:
@@ -1352,90 +1350,14 @@ class ModelProcessor:
face_visible = v0_visible | v1_visible | v2_visible
# ============ 新增:法线夹角过滤 ============
# 1. 获取面片法线(向量化计算,性能更好)
if not hasattr ( self , ' face_normals_tensor ' ) :
# 从mesh获取顶点和面片索引
vertices = np . asarray ( self . mesh . vertices ) # 形状: (V, 3)
triangles = np . asarray ( self . mesh . triangles ) # 形状: (F, 3)
# 向量化计算法线
# 获取所有三角形的顶点
v0 = vertices [ triangles [ : , 0 ] ] # 形状: (F, 3)
v1 = vertices [ triangles [ : , 1 ] ] # 形状: (F, 3)
v2 = vertices [ triangles [ : , 2 ] ] # 形状: (F, 3)
# 计算边向量
edge1 = v1 - v0
edge2 = v2 - v0
# 向量化叉积
# np.cross支持批量计算
normals = np . cross ( edge1 , edge2 )
# 计算法线长度
norms = np . linalg . norm ( normals , axis = 1 , keepdims = True )
# 避免除零
norms [ norms < 1e-6 ] = 1.0
# 归一化
normals = normals / norms
# 将退化三角形的法线设为默认值
mask = norms [ : , 0 ] < 1e-6
if np . any ( mask ) :
normals [ mask ] = np . array ( [ 0.0 , 0.0 , 1.0 ] )
# 转换为GPU张量
self . face_normals_tensor = torch . tensor ( normals , device = self . device , dtype = torch . float32 )
# 2. 计算摄像机方向(从面片中心指向摄像机)
# 获取面片顶点坐标
v0_pos = self . vertices_tensor [ v0_indices ]
v1_pos = self . vertices_tensor [ v1_indices ]
v2_pos = self . vertices_tensor [ v2_indices ]
# 计算面片中心
face_centers = ( v0_pos + v1_pos + v2_pos ) / 3.0
# 计算摄像机方向向量
camera_pos = torch . tensor ( eye , device = self . device , dtype = torch . float32 )
if len ( camera_pos . shape ) == 1 :
camera_pos = camera_pos . unsqueeze ( 0 ) # 从(3)变为(1,3)
# 方向:从面片中心指向摄像机
view_dirs = camera_pos - face_centers
view_dirs = view_dirs / torch . norm ( view_dirs , dim = 1 , keepdim = True )
# 3. 计算法线与摄像机方向的夹角
face_normals = self . face_normals_tensor
# 归一化法线
face_normals = face_normals / torch . norm ( face_normals , dim = 1 , keepdim = True )
# 计算点积(余弦值)
cos_angles = torch . sum ( face_normals * view_dirs , dim = 1 )
# 计算角度(弧度转角度)
angles_deg = torch . acos ( torch . clamp ( cos_angles , - 1.0 , 1.0 ) ) * 180.0 / torch . pi
# 4. 创建法线可见性掩码(夹角 ≤ 45度)
normal_visible_mask = angles_deg < = 40.0
# 5. 结合遮挡可见性和法线可见性
face_normal_visible = face_visible & normal_visible_mask
# ============ 法线夹角过滤结束 ============
# 使用与CPU版本相同的后续处理
shrunk_visibility = self . _shrink_face_visibility ( face_visible . cpu ( ) . numpy ( ) , 6 )
expanded_visibility = self . _expand_face_visibility ( face_visible . cpu ( ) . numpy ( ) , 0 )
shrunk_visibility2 = self . _shrink_face_visibility ( face_visible . cpu ( ) . numpy ( ) , 0 )
shrunk_visibility3 = self . _shrink_face_visibility ( face_visible . cpu ( ) . numpy ( ) , 100 )
expanded_visibility = self . _expand_face_visibility ( face_visible . cpu ( ) . numpy ( ) , 30 )
shrunk_visibility2 = self . _shrink_face_visibility ( face_visible . cpu ( ) . numpy ( ) , 50 )
expanded_edge = expanded_visibility & ~ shrunk_visibility2
delete_edge = face_visible . cpu ( ) . numpy ( ) & ~ shrunk_visibility
delete_edge2 = face_visible . cpu ( ) . numpy ( ) & ~ shrunk_visibility3
return shrunk_visibility , expanded_edge , delete_edge , delete_edge2 , face_normal_visible
return shrunk_visibility , expanded_edge , delete_edge
"""
def _gen_depth_image_gpu ( self , cam_data , render ) :
@ -1466,8 +1388,6 @@ class ModelProcessor:
@@ -1466,8 +1388,6 @@ class ModelProcessor:
visible_faces_dict = { }
edge_faces_dict = { }
delete_edge_faces_dict = { }
delete_edge_faces_dict2 = { }
face_normal_visible_dict = { }
total_start = time . time ( )
@ -1493,15 +1413,13 @@ class ModelProcessor:
@@ -1493,15 +1413,13 @@ class ModelProcessor:
# continue
start_time = time . time ( )
face_visibility , face_edge , face_delete_edge , face_delete_edge2 , face_normal_visible = self . _flag_model_gpu ( camera_data )
face_visibility , face_edge , face_delete_edge = self . _flag_model_gpu ( camera_data )
processing_time = time . time ( ) - start_time
visible_faces = np . where ( face_visibility ) [ 0 ] . tolist ( )
visible_faces_dict [ img_name ] = visible_faces
edge_faces_dict [ img_name ] = np . where ( face_edge ) [ 0 ] . tolist ( )
delete_edge_faces_dict [ img_name ] = np . where ( face_delete_edge ) [ 0 ] . tolist ( )
delete_edge_faces_dict2 [ img_name ] = np . where ( face_delete_edge2 ) [ 0 ] . tolist ( )
face_normal_visible_dict [ img_name ] = np . where ( face_normal_visible . cpu ( ) . numpy ( ) ) [ 0 ] . tolist ( )
print ( f " 图像 { img_name } 处理完成,耗时: { processing_time : .2f } 秒,可见面数量 { len ( visible_faces ) } " )
@ -1509,14 +1427,12 @@ class ModelProcessor:
@@ -1509,14 +1427,12 @@ class ModelProcessor:
print ( f " 所有图像处理完成,总耗时: { total_time : .2f } 秒 " )
print ( f " 平均每张图像耗时: { total_time / len ( images ) : .2f } 秒 " )
self . save_occlusion_data ( visible_faces_dict , edge_faces_dict , delete_edge_faces_dict , delete_edge_faces_dict2 , face_normal_visible_dict , self . asset_dir )
self . save_occlusion_data ( visible_faces_dict , edge_faces_dict , delete_edge_faces_dict , self . asset_dir )
return {
" result1 " : visible_faces_dict ,
" result2 " : edge_faces_dict ,
" result3 " : delete_edge_faces_dict ,
" result4 " : delete_edge_faces_dict2 ,
" result5 " : face_normal_visible_dict
" result3 " : delete_edge_faces_dict
}
#"""
@ -2010,6 +1926,64 @@ class ModelProcessor:
@@ -2010,6 +1926,64 @@ class ModelProcessor:
depth = render . render_to_depth_image ( z_in_view_space = True )
return np . asarray ( depth )
def sort_vertices ( vertices_original ) :
return sorted (
( v for v in vertices_original ) ,
key = lambda v : ( v . co . x , v . co . y , v . co . z )
)
def _flag_model ( self , camera_data , face_points ) :
""" 标记可见顶点 """
vertex_visible = [ ]
vertex_occlusion = [ ]
depth_images = [ ]
render = o3d . visualization . rendering . OffscreenRenderer ( camera_data [ ' width ' ] , camera_data [ ' height ' ] )
material = o3d . visualization . rendering . MaterialRecord ( )
render . scene . add_geometry ( " mesh " , self . mesh , material )
# 生成深度图
depth_image = self . _gen_depth_image ( camera_data , render )
# 计算可见性
R = self . qvec2rotmat ( camera_data [ ' qvec ' ] ) . T
eye = - R @ camera_data [ ' tvec ' ]
# eye = camera_data['tvec']
# final_visible_list, final_occlusion_list, final_vertex_difference_list = self._compute_vertex_in_frustum(
final_visible_list , final_occlusion_list = self . _compute_vertex_in_frustum (
camera_data [ ' fx ' ] , camera_data [ ' fy ' ] ,
camera_data [ ' cx ' ] , camera_data [ ' cy ' ] ,
R , eye ,
camera_data [ ' height ' ] , camera_data [ ' width ' ] ,
depth_image , camera_data [ ' qvec ' ] , camera_data [ ' tvec ' ]
)
print ( " _flag_model " , len ( final_occlusion_list ) , len ( self . mesh . vertices ) , len ( self . mesh . vertex_colors ) )
# 获取三角形面片数组
triangles = np . asarray ( self . mesh . triangles )
face_visible_bitmap = np . zeros ( len ( triangles ) , dtype = bool )
# 遍历所有面片
for face_idx , face in enumerate ( triangles ) :
v0 , v1 , v2 = face
face_visible_bitmap [ face_idx ] = any ( [ # any all
final_visible_list [ v0 ] ,
final_visible_list [ v1 ] ,
final_visible_list [ v2 ]
] )
shrunk_visibility = self . _shrink_face_visibility ( face_visible_bitmap , 6 ) # 6 10
expanded_visibility = self . _expand_face_visibility ( face_visible_bitmap , 30 )
shrunk_visibility2 = self . _shrink_face_visibility ( face_visible_bitmap , 50 )
expanded_edge = expanded_visibility & ~ shrunk_visibility2
delete_edge = face_visible_bitmap & ~ shrunk_visibility
return shrunk_visibility , expanded_edge , delete_edge
def _flag_contour ( self , camera_data , face_points ) :
""" 标记可见顶点 """
vertex_visible = [ ]
@ -2099,11 +2073,97 @@ class ModelProcessor:
@@ -2099,11 +2073,97 @@ class ModelProcessor:
face_visible_bitmap = np . ones ( len ( triangles ) , dtype = bool ) # 临时填充
return face_visible_bitmap , face_edge
"""
def _mask_face_occlusion ( self ) :
# 读取相机数据
cameras = read_cameras_text ( os . path . join ( self . pose_path , " cameras.txt " ) )
images = read_images_text ( os . path . join ( self . pose_path , " images.txt " ) )
# cameras = read_cameras_text(os.path.join(self.pose_path, "backup_cameras.txt"))
# images = read_images_text(os.path.join(self.pose_path, "backup_images.txt"))
face_points_sorted_path = os . path . join ( self . pose_path , " face_points_sorted.txt " )
print ( " face_points_sorted_path= " , face_points_sorted_path )
#face_points = read_int_text(face_points_sorted_path)
face_points = read_indices_from_file ( face_points_sorted_path )
# face_points = {}
camera_data = { }
for img in images . values ( ) :
if self . mask_image == img . name [ : - 4 ] :
camera = cameras [ img . camera_id ]
camera_data = {
" qvec " : img . qvec ,
" tvec " : img . tvec ,
" fx " : camera . params [ 0 ] ,
" fy " : camera . params [ 1 ] ,
" cx " : camera . params [ 2 ] ,
" cy " : camera . params [ 3 ] ,
" width " : camera . width ,
" height " : camera . height ,
" name " : img . name [ : - 4 ]
}
# print(face_points)
self . _flag_model ( camera_data , face_points )
"""
def _mask_occlusion ( self ) :
# 读取相机数据
cameras = read_cameras_text ( os . path . join ( self . pose_path , " cameras.txt " ) )
images = read_images_text ( os . path . join ( self . pose_path , " images.txt " ) )
camera_data = { }
countour_faces_dict = { }
visible_faces_dict = { }
edge_faces_dict = { }
delete_edge_faces_dict = { }
total_start = time . time ( )
n = 0
for img in images . values ( ) :
camera = cameras [ img . camera_id ]
camera_data = {
" qvec " : img . qvec ,
" tvec " : img . tvec ,
" fx " : camera . params [ 0 ] ,
" fy " : camera . params [ 1 ] ,
" cx " : camera . params [ 2 ] ,
" cy " : camera . params [ 3 ] ,
" width " : camera . width ,
" height " : camera . height ,
" name " : img . name [ : - 4 ]
}
img_name = img . name [ : - 4 ]
# if (img_name!="73_8" and img_name!="52_8" and img_name!="62_8"):
# if (img_name!="52_8" and img_name!="62_8"):
# if (img_name!="52_8"):
# continue
start_time = time . time ( )
face_visibility , face_edge , face_delete_edge = self . _flag_model ( camera_data , None )
processing_time = time . time ( ) - start_time
visible_faces = np . where ( face_visibility ) [ 0 ] . tolist ( )
visible_faces_dict [ img . name [ : - 4 ] ] = visible_faces
edge_faces_dict [ img . name [ : - 4 ] ] = np . where ( face_edge ) [ 0 ] . tolist ( )
delete_edge_faces_dict [ img . name [ : - 4 ] ] = np . where ( face_delete_edge ) [ 0 ] . tolist ( )
n + = 1
print ( f " 图像= { img_name } ,耗时= { processing_time : .2f } 秒,可见面数= { len ( visible_faces ) } " )
total_time = time . time ( ) - total_start
print ( f " 所有图像处理完成,总耗时: { total_time : .2f } 秒 " )
print ( f " 平均每张图像耗时: { total_time / len ( images ) : .2f } 秒 " )
self . save_occlusion_data ( visible_faces_dict , edge_faces_dict , delete_edge_faces_dict , self . asset_dir )
return { " result1 " : visible_faces_dict , " result2 " : edge_faces_dict , " result3 " : delete_edge_faces_dict }
def save_occlusion_data ( self , result1 : Dict [ str , List [ int ] ] ,
result2 : Dict [ str , List [ int ] ] ,
result3 : Dict [ str , List [ int ] ] ,
result4 : Dict [ str , List [ int ] ] ,
result5 : Dict [ str , List [ int ] ] ,
result3 : Dict [ str , List [ int ] ] ,
base_path : str ) - > None :
"""
保存遮挡数据到文件
@ -2114,8 +2174,6 @@ class ModelProcessor:
@@ -2114,8 +2174,6 @@ class ModelProcessor:
result3 : 删除边面字典 , 包含图像名称和对应的删除边面列表
base_path : 基础文件路径
"""
os . makedirs ( base_path , exist_ok = True )
print ( f " save_occlusion_data { base_path } , { len ( result1 ) } , { len ( result2 ) } , { len ( result3 ) } " )
@ -2138,20 +2196,10 @@ class ModelProcessor:
@@ -2138,20 +2196,10 @@ class ModelProcessor:
delete_edge_faces_map : Dict [ str , Set [ int ] ] = { }
for image_name , face_list in result3 . items ( ) :
delete_edge_faces_map [ image_name ] = set ( face_list )
delete_edge_faces_map2 : Dict [ str , Set [ int ] ] = { }
for image_name , face_list in result4 . items ( ) :
delete_edge_faces_map2 [ image_name ] = set ( face_list )
face_normal_visible_map : Dict [ str , Set [ int ] ] = { }
for image_name , face_list in result5 . items ( ) :
face_normal_visible_map [ image_name ] = set ( face_list )
# 保存 visible_faces_map
try :
file_name = " _visible_faces_map.txt "
file_path = Path ( base_path ) / file_name
with open ( file_path , " w " , encoding = ' utf-8 ' ) as map_file :
with open ( base_path + " /_visible_faces_map.txt " , " w " , encoding = ' utf-8 ' ) as map_file :
for image_name , face_set in visible_faces_map . items ( ) :
# 写入图像名称和所有面ID,用空格分隔
line = image_name + " " + " " . join ( str ( face ) for face in face_set ) + " \n "
@ -2161,9 +2209,7 @@ class ModelProcessor:
@@ -2161,9 +2209,7 @@ class ModelProcessor:
# 保存 face_visible_relative
try :
file_name = " _face_visible_relative.txt "
file_path = Path ( base_path ) / file_name
with open ( file_path , " w " , encoding = ' utf-8 ' ) as relative_file :
with open ( base_path + " /_face_visible_relative.txt " , " w " , encoding = ' utf-8 ' ) as relative_file :
for face in face_visible_relative :
relative_file . write ( str ( face ) + " \n " )
except IOError as e :
@ -2171,9 +2217,7 @@ class ModelProcessor:
@@ -2171,9 +2217,7 @@ class ModelProcessor:
# 保存 edge_faces_map
try :
file_name = " _edge_faces_map.txt "
file_path = Path ( base_path ) / file_name
with open ( file_path , " w " , encoding = ' utf-8 ' ) as map_file2 :
with open ( base_path + " /_edge_faces_map.txt " , " w " , encoding = ' utf-8 ' ) as map_file2 :
for image_name , face_set in edge_faces_map . items ( ) :
line = image_name + " " + " " . join ( str ( face ) for face in face_set ) + " \n "
map_file2 . write ( line )
@ -2182,37 +2226,13 @@ class ModelProcessor:
@@ -2182,37 +2226,13 @@ class ModelProcessor:
# 保存 delete_edge_faces_map
try :
file_name = " _delete_edge_faces_map.txt "
file_path = Path ( base_path ) / file_name
with open ( file_path , " w " , encoding = ' utf-8 ' ) as map_file3 :
with open ( base_path + " /_delete_edge_faces_map.txt " , " w " , encoding = ' utf-8 ' ) as map_file3 :
for image_name , face_set in delete_edge_faces_map . items ( ) :
line = image_name + " " + " " . join ( str ( face ) for face in face_set ) + " \n "
map_file3 . write ( line )
except IOError as e :
print ( f " Error writing delete_edge_faces_map file: { e } " )
# 保存 delete_edge_faces_map2
try :
file_name = " _delete_edge_faces_map2.txt "
file_path = Path ( base_path ) / file_name
with open ( file_path , " w " , encoding = ' utf-8 ' ) as map_file4 :
for image_name , face_set in delete_edge_faces_map2 . items ( ) :
line = image_name + " " + " " . join ( str ( face ) for face in face_set ) + " \n "
map_file4 . write ( line )
except IOError as e :
print ( f " Error writing delete_edge_faces_map2 file: { e } " )
# 保存 face_normal_visible_map
try :
file_name = " _face_normal_visible_map.txt "
file_path = Path ( base_path ) / file_name
with open ( file_path , " w " , encoding = ' utf-8 ' ) as map_file5 :
for image_name , face_set in face_normal_visible_map . items ( ) :
line = image_name + " " + " " . join ( str ( face ) for face in face_set ) + " \n "
map_file5 . write ( line )
except IOError as e :
print ( f " Error writing _face_normal_visible_map file: { e } " )
def process ( self ) :
print ( " process " )