三维重构终版

This commit is contained in:
2025-11-02 21:36:35 +08:00
parent f91b09da9d
commit f39009b853
126 changed files with 2870 additions and 2 deletions

186
3D_construction/main.py Normal file
View File

@@ -0,0 +1,186 @@
import os
import cv2
import numpy as np
from script.yolo_detector import detect_crop_area
from script.linknet_segmentor import segment_and_find_endpoints
from script.reconstruction import visualize_reconstructed_seams, reconstruct_points
from script.pose_estimation import get_ground_truth_seams, reproject_to_object_coords # 我们只需要真值
# 导入我们最终的重建流程
from script.final_reconstruction import final_reconstruction_pipeline, merge_seams
import itertools # 确保导入itertools
from script.global_optimizer import run_global_optimization, merge_seams
from script.pose_estimation import get_ground_truth_seams
from script.reconstruction import visualize_reconstructed_seams
def run_full_recognition_pipeline():
"""
运行完整的识别流程YOLO定位 -> LinkNet分割 -> 端点提取。
"""
# 1. 定义路径
base_dir = os.path.dirname(os.path.abspath(__file__))
data_map = {
'up': {
'l_img': os.path.join(base_dir, 'data', 'origin', 'up', 'l1.jpeg'),
'r_img': os.path.join(base_dir, 'data', 'origin', 'up', 'r1.jpeg'),
'yolo_model': os.path.join(base_dir, 'module', 'yolov8', 'up.pt'),
'linknet_models': {
'line1': os.path.join(base_dir, 'module', 'linknet', 'best_linknet_up_model_line1.pth'),
'line2': os.path.join(base_dir, 'module', 'linknet', 'best_linknet_up_model_line2.pth')
}
},
'bottom': {
'l_img': os.path.join(base_dir, 'data', 'origin', 'bottom', 'l1.jpeg'),
'r_img': os.path.join(base_dir, 'data', 'origin', 'bottom', 'r1.jpeg'),
'yolo_model': os.path.join(base_dir, 'module', 'yolov8', 'bottom.pt'),
'linknet_models': {
'line1': os.path.join(base_dir, 'module', 'linknet', 'best_linknet_bottom_model_line1.pth'),
'line2': os.path.join(base_dir, 'module', 'linknet', 'best_linknet_bottom_model_line2.pth')
}
}
}
output_dir = os.path.join(base_dir, 'data', 'processed')
os.makedirs(output_dir, exist_ok=True)
all_endpoints = {}
for part, paths in data_map.items():
print(f"\n--- Processing '{part}' part ---")
for img_path, side in [(paths['l_img'], 'l'), (paths['r_img'], 'r')]:
print(f"\n-- Analyzing image: {os.path.basename(img_path)} --")
crop_box = detect_crop_area(img_path, paths['yolo_model'])
if not crop_box:
print(f"Skipping further processing for {os.path.basename(img_path)}.")
continue
original_image_vis = cv2.imread(img_path)
for line_name, linknet_path in paths['linknet_models'].items():
endpoints = segment_and_find_endpoints(original_image_vis, crop_box, linknet_path)
if endpoints:
start_pt, end_pt = endpoints
result_key = f"{part}_{side}_{line_name}"
all_endpoints[result_key] = {'start': start_pt, 'end': end_pt}
# --- 在可视化图像上绘制结果 (增强版) ---
# 1. 绘制端点圆圈
cv2.circle(original_image_vis, start_pt, 15, (0, 255, 0), -1) # 绿色起点
cv2.circle(original_image_vis, end_pt, 15, (0, 0, 255), -1) # 红色终点
# 2. 绘制连接线
cv2.line(original_image_vis, start_pt, end_pt, (255, 0, 0), 4)
# 3. 添加文本标签
# 计算线段中点作为文本放置位置
mid_point = ((start_pt[0] + end_pt[0]) // 2, (start_pt[1] + end_pt[1]) // 2)
# 在中点上方放置文本
text_pos = (mid_point[0], mid_point[1] - 20)
cv2.putText(original_image_vis,
result_key,
text_pos,
cv2.FONT_HERSHEY_SIMPLEX,
2, # 字体大小
(255, 255, 0), # 字体颜色 (青色)
4, # 字体粗细
cv2.LINE_AA)
# 绘制YOLO框并保存最终的可视化结果
cv2.rectangle(original_image_vis, (crop_box[0], crop_box[1]), (crop_box[2], crop_box[3]), (0, 255, 255), 4)
save_path = os.path.join(output_dir, f'{part}_{side}_final_result.jpg')
cv2.imwrite(save_path, original_image_vis)
print(f"Saved final visualization to {save_path}")
# 3. 打印总结
print("\n--- Final Endpoints Summary (in original image coordinates) ---")
for name, points in all_endpoints.items():
print(f"{name}: Start={points['start']}, End={points['end']}")
return all_endpoints
def run_3d_reconstruction(all_2d_endpoints):
"""
根据识别出的2D端点重建出三维焊缝。
"""
print("\n--- Starting 3D Reconstruction ---")
# 这个字典将存储最终的三维坐标
reconstructed_seams_3d = {}
# 需要重建的焊缝对
# 例如:'up_line1' 对应 up_l_line1 和 up_r_line1
seam_pairs = ['up_line1', 'up_line2', 'bottom_line1', 'bottom_line2']
for seam_name in seam_pairs:
key_L = f"{seam_name.split('_')[0]}_l_{seam_name.split('_')[1]}" # e.g., 'up_l_line1'
key_R = f"{seam_name.split('_')[0]}_r_{seam_name.split('_')[1]}" # e.g., 'up_r_line1'
# 检查左右相机的点是否都已识别
if key_L not in all_2d_endpoints or key_R not in all_2d_endpoints:
print(f"Warning: Missing points for seam '{seam_name}'. Cannot reconstruct.")
continue
# 准备输入点列表:[start_point, end_point]
points_L = [all_2d_endpoints[key_L]['start'], all_2d_endpoints[key_L]['end']]
points_R = [all_2d_endpoints[key_R]['start'], all_2d_endpoints[key_R]['end']]
# 调用重建函数
# 假设你的图像尺寸是 4000x3000如果不是请修改
# 这是一个重要的参数,需要与标定时使用的图像尺寸一致!
points_3d = reconstruct_points(points_L, points_R, image_size=(4000, 3000))
reconstructed_seams_3d[seam_name] = {
'start_3d': points_3d[0],
'end_3d': points_3d[1]
}
# --- 打印最终的三维坐标结果 ---
print("\n--- Final 3D Seam Endpoints (in Left Camera Coordinate System, unit: mm) ---")
for name, points in reconstructed_seams_3d.items():
start_str = np.array2string(points['start_3d'], formatter={'float_kind': lambda x: "%.3f" % x})
end_str = np.array2string(points['end_3d'], formatter={'float_kind': lambda x: "%.3f" % x})
print(f"{name}:")
print(f" Start 3D: {start_str}")
print(f" End 3D: {end_str}")
return reconstructed_seams_3d
def run_new_reconstruction_pipeline(all_2d_endpoints):
"""
使用 solvePnP 的全新重建和拼接流程。
"""
print("\n--- Starting NEW Reconstruction Pipeline (with solvePnP) ---")
# --- 处理上半部分 ---
print("\nProcessing 'up' part...")
reconstructed_up = reproject_to_object_coords(all_2d_endpoints, all_2d_endpoints, part_type='up')
# --- 处理下半部分 ---
print("\nProcessing 'bottom' part...")
reconstructed_bottom = reproject_to_object_coords(all_2d_endpoints, all_2d_endpoints, part_type='bottom')
# --- 合并结果 ---
final_reconstructed_seams = {}
if reconstructed_up:
final_reconstructed_seams.update(reconstructed_up)
if reconstructed_bottom:
final_reconstructed_seams.update(reconstructed_bottom)
return final_reconstructed_seams
if __name__ == '__main__':
final_2d_endpoints = run_full_recognition_pipeline()
ground_truth = get_ground_truth_seams()
final_4_seams = {}
if final_2d_endpoints:
# 直接调用全局优化
final_4_seams = run_global_optimization(final_2d_endpoints, ground_truth)
final_3_seam_model = {}
if final_4_seams:
final_3_seam_model = merge_seams(final_4_seams)