节点修改方法:
节点7的正确理解是:
-
Step 1:ransac_perpendicular_corner → 底板L形角,补全出 base_plate_polyline(这就是"矩形多段线")
-
Step 2:删除底板层
-
Step 3:ransac_circle_square → 圆孔 + 同心正方形(即 case8 已有的函数)
原方案写成 ransac_circle_rectangle / ransac_circle_square 是多余的歧义,节点7的方法兰是正方形,应固定用 ransac_circle_square。
完整修改方案(终版)
每个节点的算法对应:
所有节点 Step 1 完全相同,只有 Step 2 不同。
改动总览(9处):
- model_est.py --- 新增 estimate_coaxial_circles
位置:紧接 estimate_concentric_coplanar_circles 之后,归属注释"第2层"。
4点采样逻辑:
pts0:3 → fit_circle → (center1, normal=共轴方向, radius1)
pts3 → 到轴线距离 → radius2
pts3 → 在轴方向的投影偏移量 + center1_xy → center2
校验(缺一不可):
-
radius2 > 0 且有限
-
两圆心沿 normal 方向的高度差 > min_gap(防退化为共面)
返回格式(与现有 estimate_concentric_coplanar_circles 完全一致):
(circle1, circle2) # 每个 circle = (center: ndarray(3,), normal: ndarray(3,), radius: float)
- core/workers.py --- 新增 "coaxial_circles" 分支
位置:_trial_worker 里,elif model_type == "perpendicular_corner": 之前
elif model_type == "coaxial_circles":
c1, c2 = estimate_coaxial_circles(sample)
if c1 is None or c2 is None:
return None, -np.inf, None, 0
model = (c1, c2)
shapes = {"circles": [
{"center": c10.tolist(), "normal": c11.tolist(), "radius": c12},
{"center": c20.tolist(), "normal": c21.tolist(), "radius": c22},
]}
文件头 import 增加 estimate_coaxial_circles。
_trial_worker_fixed_normal 本次不改。
- core/models.py --- 新增 ransac_coaxial_circles
位置:紧接 ransac_concentric_circles 之后
def ransac_coaxial_circles(points, max_iter=1000, threshold=1.0,
soft_threshold=False, temperature=1.0,
n_workers=None):
"""同轴双圆(同轴不共面)。4点采样:3点定轴,第4点定圆2高度和半径。"""
return ransac(points, 4, max_iter, threshold,
soft_threshold, temperature, "coaxial_circles",
n_workers=n_workers)
- core/init.py
import 和 all 各加一行 ransac_coaxial_circles,风格与现有保持一致。
- viz/scenes.py --- 新增2个函数
5a. visualize_coaxial_circles(紧接 visualize_concentric_circles 之后)
同轴双圆专用可视化(两圆不共面,有高度差):
内点红色 / 外点灰色:make_inlier_pcd
圆1(低圆):make_circle_lineset(c10, c11, c12, BLUE)
圆2(高圆):make_circle_lineset(c20, c21, c22, BLUE)
共同轴线箭头:make_normal_arrow(c10, c11, 高度差) 从低圆圆心出发
低圆圆心标注:make_center_sphere(c10)
坐标系:frame_at_centroid(points)
5b. visualize_plate_node_result(文件末尾)
底板 + 目标几何联合可视化,一个窗口展示全部:
着色:
底板 L形角 内点 → 绿色 0.0, 0.8, 0.0
目标几何体 内点 → 红色 1.0, 0.0, 0.0
其余点 → 灰色 0.6, 0.6, 0.6
底板部分(固定):
L形角两段线段(绿色)+ 角点绿球
目标几何部分(按 node_type):
"big_ring" / "circular_flange":两个蓝色圆 lineset + 法向箭头 + 圆心球
"big_ring_back" / "circular_flange_back":两个蓝色圆 lineset(不同高度)+ 轴线箭头
"frame_flange":内外两个蓝色矩形 lineset + 法向箭头
"square_flange":蓝色圆 lineset + 蓝色正方形 lineset
签名:
def visualize_plate_node_result(points, base_corner, base_mask,
geometry, geom_mask, node_type,
title="节点测量结果"):
- viz/init.py
from .scenes import (...) 和 all 各增加:
-
visualize_coaxial_circles
-
visualize_plate_node_result
- pipeline/node_measurement.py(新建)
Step 1 : ransac_perpendicular_corner → base_corner(底板L形角,迭代数 corner_iter)
Step 2 : 由L形角两端点补全底板矩形顶点 → base_plate_polyline
corner → far_A → (far_A + far_B - corner) → far_B → corner
Step 3 : remove_plane_points(plane来自base_corner"plane") → 删除底板整层
Step 4 : 按 node_type 选择 RANSAC 函数,拟合目标几何(迭代数 geom_iter)
Step 5 : mask 映射回原始 points,组装返回字典
node_type → RANSAC 接口:
_GEOMETRY_FN = {
"big_ring": ransac_concentric_circles,
"big_ring_back": ransac_coaxial_circles,
"circular_flange": ransac_concentric_circles,
"circular_flange_back": ransac_coaxial_circles,
"frame_flange": ransac_concentric_rectangles,
"square_flange": ransac_circle_square,
}
函数签名:
def run_plate_node_pipeline(
points, node_type,
threshold=5.0, soft_threshold=True, temperature=3.0,
corner_iter=100000, geom_iter=200000,
plane_removal_threshold=20.0,
**geom_kwargs):
返回字典:
{
"base_corner": base_corner, # L形角模型
"base_plate_polyline": ..., # 底板闭合顶点列表
"geometry": geometry_model, # 目标几何体
"base_mask_full": base_mask, # 底板内点掩码
"geometry_inliers_full": geom_inliers, # 目标内点掩码
"geometry_count": count,
}
- pipeline/init.py
新增 run_plate_node_pipeline 的 import 和 all 条目。
- main.py --- 新增 case12_plate_node_pipeline
一个 case 覆盖全部节点,通过 node_type 切换:
def case12_plate_node_pipeline():
"""Case 12 通用节点测量流水线(改 node_type 切换节点2~7)。"""
pts = load_point_cloud(r"D:\ransac_v4\data\...\xxx.pcd")
print(f"case 12 原始输入点数:{len(pts)}")
visualize_raw(pts, title="Before: 节点测量")
start = time.perf_counter()
result = run_plate_node_pipeline(
pts,
node_type="big_ring", # ← 改此处切换节点
threshold=5.0, soft_threshold=True, temperature=3.0,
corner_iter=100000, geom_iter=200000,
plane_removal_threshold=20.0,
)
elapsed = time.perf_counter() - start
print(f"Case 12 流水线总耗时 {elapsed:.2f}s")
print 各节点关键参数(角点、内外径/半宽高、内点数等)
visualize_plate_node_result(
pts,
base_corner=result"base_corner",
base_mask=result"base_mask_full",
geometry=result"geometry",
geom_mask=result"geometry_inliers_full",
node_type="big_ring", # ← 与上面保持一致
title="After: 节点测量",
)
main 块增加:
Case 12 通用节点测量流水线
case12_plate_node_pipeline()
风险点:
R1:底板与目标几何高度差太小,remove_plane_points 误删目标点
缓解方式:plane_removal_threshold 暴露为参数
R2:同轴双圆4点采样噪声敏感,退化为共面
缓解方式:min_gap 校验,不稳定可后续改6点,不破坏接口
R3:base_plate_polyline 由L角两端补全,仅适合矩形底板
缓解方式:当前约束明确,不规则底板后续扩展
R4:visualize_plate_node_result 内部按 node_type 分派
缓解方式:与现有 visualize_three_pairs_concentric_circles 风格一致,可接受
节点的真实关键参数和我已经实现的方法能不能实现真实关键参数完成:
❯ 现在需要你根据我给你的keyparam,判断我实现的方法,返回的模型里面能不能满足下面真实的参数,将下面所有的关键参数完成实例化:2
(盖板)大圆环
通常是油箱盖板上的,用于连接圆柱形升高座的密封圈。
圆环
平板
圆环与平板共面而且同轴
ring_inner_diameter
圆环内径
ring_outer_diameter
圆环外径
ring_center_x
ring_center_y
ring_center_z
圆环上表面中心点
ring_normal_x
ring_normal_y
ring_normal_z
圆环上表面法向
base_plate_polyline
底板外轮廓多段线表示
Polyline定义在geometry.py中
底板本身开圆孔,其直径比圆环的外径小,比内径大
共面前提下高度即为厚度
@dataclass
class LineSegment:
"""A segment between two 3D points.
``None`` means the endpoint is currently unknown or will be inferred by a
later recognizer/reasoner step.
"""
start: OptionalVec3 = None
end: OptionalVec3 = None
metadata: dictstr, Any = field(default_factory=dict)
@dataclass
class SegmentConstraint:
"""Constraint between two segments in the same polyline-like primitive."""
segment_a: int
segment_b: int
type: SegmentConstraintType
metadata: dictstr, Any = field(default_factory=dict)
@dataclass
class Polyline(Primitive):
primitive_type: ClassVarPrimitiveType = PrimitiveType.POLYLINE
segments: listLineSegment = field(default_factory=list)
segment_constraints: listSegmentConstraint = field(default_factory=list)
closed: bool = False
@property
def segment_count(self) -> int:
return len(self.segments)
Polyline是由一系列 LineSegment(线段)首尾拼接而成的路径。每个线段包含起点和终点, 其次还会存储线段的约束关系,比如垂直平行等
通常和圆柱形升高座尺寸相似,常见直径约400~600mm,也存在特例,一般是连接其他的管道或检测装置:
搭接板板厚20~30mm。
圆环板厚20-30mm
有平整度要求,要实现气密性,所以会用铣边机铣过,表面是亮面。
可行 3
(滴答)
3 大圆环背部
image-2026-3-6_15-25-14.png
底板带圆环一起翻转
圆环
平板
ring_inner_diameter
圆环内径
plate_hole_diameter
平板孔径
center_x
center_y
center_z
平板孔面中心点
ring_center_x
ring_center_y
ring_center_z
圆环内孔中心点
normal_x
normal_y
normal_z
圆环下表面法向
base_plate_polyline
底板外轮廓多段线表示
同上 可行 3
2026年5月19日
朱琳
(滴答)
4 搭接圆法兰
圆形法兰
平板
flange_inner_diameter
法兰内径
flange_outer_diameter
法兰外径
flange_center_x
flange_center_y
flange_center_z
法兰上表面中心点
flange_normal_x
flange_normal_y
flange_normal_z
法兰上表面法向
base_plate_polyline
底板外轮廓多段线表示
底板不需要建孔
法兰厚度是 max(高度差,法兰先验厚度)
需要区分是连接升高座的,还是连接管道的。
连接管道的板厚一般在10~20mm,连接升高座的板厚更大20~30mm。
尺寸多变,直径100~600mm。
可行 3
2026年5月19日
梅景
(滴答)
5 搭接圆法兰背部
圆形法兰
平板
flange_inner_diameter
法兰内径
plate_hole_diameter
平板孔径
center_x
center_y
center_z
平板孔面中心点
flange_center_x
flange_center_y
flange_center_z
法兰内孔中心点
normal_x
normal_y
normal_z
圆环下表面法向
base_plate_polyline
底板外轮廓多段线表示
可行 3
2026年5月19日
梅景
(滴答)
6 方框法兰
常见的作用是视窗,安装透明玻璃,用于观察油箱内部液面的情况或者变压器某些度数。
方框法兰
平板
同轴共面
flange_rectangle
方形法兰两个矩形的多段线表示
base_plate_polyline
底板外轮廓多段线表示
螺栓孔用先验知识建模
内部没有焊缝
板厚20~30mm。
尺寸宽约300~500mm,长500~1000mm甚至会更长
可行
3
朱琳 (滴答)
7 搭接方法兰
方法兰
平板
flange_square
方形法兰矩形的多段线表示
inner_diameter
法兰内径
flange_center_x
flange_center_y
flange_center_z
法兰上表面中心点
flange_normal_x
flange_normal_y
flange_normal_z
法兰上表面法向
base_plate_polyline
底板的多段线表示
螺栓孔用先验知识建模
板厚10~20mm,边长100~150mm,上方可能带螺栓可能不带
导角有三类:
(1)无导角
(2)圆弧导角,半径10~20mm
(3)直边导角,边长10~20mm
可行
初始位置x为长轴
3
,帮我检查是否满足,不需要修改,告诉我即可