Compare commits

...
Author SHA1 Message Date
hesuicong 1421d21597 进一步优化 2026-05-30 15:18:09 +08:00
hesuicong 3693365bdf 算法优化 2026-05-29 18:05:56 +08:00
hesuicong 03929e5b95 视图排序优化 2026-05-28 18:13:42 +08:00
hesuicong 1086eb09c5 优化染色版本 2026-05-28 10:54:42 +08:00
hesuicong 7d0487ea30 针对小黄点过多和手指染色问题的参数优化 2026-05-25 14:40:16 +08:00
hesuicong cbe065a6a1 参数进一步优化 2026-05-22 17:42:12 +08:00
hesuicong 488f5a3f93 颜色溢出进一步优化 2026-05-21 14:57:14 +08:00
hesuicong e18f91e894 颜色溢出优化 2026-05-20 17:50:50 +08:00
hesuicong eafae796c2 删除保留的函数,简化 2026-04-16 09:16:33 +08:00
hesuicong 35ac5deff9 参数优化 2026-04-14 14:47:15 +08:00
hesuicong f9e7f3f18b 解决线上问题 2026-04-11 17:59:47 +08:00
hesuicong d035a20e91 参数优化 2026-04-03 10:24:05 +08:00
hesuicong d11d956b58 参数优化 2026-04-01 16:39:20 +08:00
hesuicong 743835d1b0 参数优化 2026-03-27 17:41:10 +08:00
hesuicong 4968fcc954 优化参数 2026-03-27 11:40:58 +08:00
hesuicong dbe42abf1f 优化脸色发青问题 2026-03-26 17:28:05 +08:00
hesuicong 5685a46331 处理脸色发青问题 2026-03-24 16:47:59 +08:00
hesuicong bbddc87ccc 优化过滤算法 2026-03-23 11:05:51 +08:00
hesuicong 634590e6d4 处理脸部青黄问题 2026-03-21 15:58:56 +08:00
hesuicong 955419e110 参数优化 2026-03-19 16:43:04 +08:00
hesuicong 1483610ed5 优化参数 2026-03-16 09:39:00 +08:00
hesuicong 6bd6b27f17 鼻子黑 2026-03-11 18:16:15 +08:00
hesuicong 37ebcdf0fd 鼻子黑的问题优化 2026-03-11 18:08:17 +08:00
hesuicong ef09d2521a 白痕优化 2026-03-06 17:05:01 +08:00
hesuicong 60f024abaf 优化性能 2026-03-03 16:02:18 +08:00
hesuicong 469f3df88d 优化性能 2026-03-03 16:01:18 +08:00
hesuicong bc461bd595 添加调试单视图信息 2026-02-24 17:43:34 +08:00
3 changed files with 911 additions and 376 deletions

No files matched your search

+3
View File
@@ -65,6 +65,7 @@ public:
std::map<std::string, std::unordered_set<int>> visible_faces_map;
std::map<std::string, std::unordered_set<int>> edge_faces_map;
std::map<std::string, std::unordered_set<int>> delete_edge_faces_map;
std::map<std::string, std::unordered_set<int>> face_normal_visible_map;
std::unordered_set<int> face_visible_relative;
public:
@@ -163,6 +164,7 @@ public:
std::unordered_set<int>& face_visible_relative,
std::map<std::string, std::unordered_set<int>>& edge_faces_map,
std::map<std::string, std::unordered_set<int>>& delete_edge_faces_map,
std::map<std::string, std::unordered_set<int>>& face_normal_visible_map,
std::string& basePath);
// Mesh texturing
@@ -176,6 +178,7 @@ public:
bool is_face_visible_relative(int face_index);
bool is_face_edge(const std::string& image_name, int face_index);
bool is_face_delete_edge(const std::string& image_name, int face_index);
bool is_face_normal_visible_map(const std::string& image_name, int face_index);
void SegmentMeshBasedOnCurvature(Mesh::FaceIdxArr& regionMap, float curvatureThreshold);
+809 -223
View File
File diff suppressed because it is too large. Load diff
+99 -153
View File
@@ -1352,14 +1352,88 @@ 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(), 30)
shrunk_visibility2 = self._shrink_face_visibility(face_visible.cpu().numpy(), 50)
shrunk_visibility = self._shrink_face_visibility(face_visible.cpu().numpy(), 12)
expanded_visibility = self._expand_face_visibility(face_visible.cpu().numpy(), 0)
shrunk_visibility2 = self._shrink_face_visibility(face_visible.cpu().numpy(), 0)
expanded_edge = expanded_visibility & ~shrunk_visibility2
delete_edge = face_visible.cpu().numpy() & ~shrunk_visibility
return shrunk_visibility, expanded_edge, delete_edge
return shrunk_visibility, expanded_edge, delete_edge, face_normal_visible
"""
def _gen_depth_image_gpu(self, cam_data, render):
@@ -1390,6 +1464,7 @@ class ModelProcessor:
visible_faces_dict = {}
edge_faces_dict = {}
delete_edge_faces_dict = {}
face_normal_visible_dict = {}
total_start = time.time()
@@ -1415,13 +1490,14 @@ class ModelProcessor:
# continue
start_time = time.time()
face_visibility, face_edge, face_delete_edge = self._flag_model_gpu(camera_data)
face_visibility, face_edge, face_delete_edge, face_normal_visible = 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()
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)}")
@@ -1429,12 +1505,13 @@ 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, self.asset_dir)
self.save_occlusion_data(visible_faces_dict, edge_faces_dict, delete_edge_faces_dict, face_normal_visible_dict, self.asset_dir)
return {
"result1": visible_faces_dict,
"result2": edge_faces_dict,
"result3": delete_edge_faces_dict
"result3": delete_edge_faces_dict,
"result4": face_normal_visible_dict
}
#"""
@@ -1928,64 +2005,6 @@ 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 = []
@@ -2075,97 +2094,10 @@ 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]],
base_path: str) -> None:
"""
保存遮挡数据到文件
@@ -2201,6 +2133,9 @@ class ModelProcessor:
for image_name, face_list in result3.items():
delete_edge_faces_map[image_name] = set(face_list)
face_normal_visible_map: Dict[str, Set[int]] = {}
for image_name, face_list in result4.items():
face_normal_visible_map[image_name] = set(face_list)
# 保存 visible_faces_map
try:
@@ -2246,6 +2181,17 @@ class ModelProcessor:
except IOError as e:
print(f"Error writing delete_edge_faces_map 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_file4:
for image_name, face_set in face_normal_visible_map.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_map file: {e}")
def process(self):
print("process")