点准了

This commit is contained in:
robofish 2025-07-11 22:53:01 +08:00
parent 88c5e2b6fb
commit 21d105a0fc

View File

@ -7,6 +7,7 @@ import sensor_msgs_py.point_cloud2 as pc2
from visualization_msgs.msg import Marker
import std_msgs.msg
import geometry_msgs.msg
import collections
class RectangleDetector(Node):
def __init__(self):
@ -20,11 +21,37 @@ class RectangleDetector(Node):
self.marker_pub = self.create_publisher(Marker, '/rectangle_marker', 10)
# 可选:发布原始点云
self.cloud_pub = self.create_publisher(PointCloud2, '/rectangle_cloud', 10)
self.history = collections.deque(maxlen=5)
self.last_bbox = None
self.last_time = None
# 目标矩形尺寸(单位:米)
self.length = 1.8
self.width = 1.05
self.thickness = 0.04
def filter_points(self, points):
# 统计滤波:去除离群点
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
cl, ind = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=2.0)
filtered = np.asarray(cl.points)
# 半径滤波
cl2, ind2 = cl.remove_radius_outlier(nb_points=10, radius=0.05)
return np.asarray(cl2.points)
def smooth_bbox(self, bbox):
# 保存历史中心和尺寸
center = bbox.center
extent = bbox.extent
self.history.append((center, extent))
# 计算加权平均
centers = np.array([h[0] for h in self.history])
extents = np.array([h[1] for h in self.history])
smooth_center = np.mean(centers, axis=0)
smooth_extent = np.mean(extents, axis=0)
bbox.center = smooth_center
bbox.extent = smooth_extent
return bbox
def publish_marker(self, bbox):
@ -33,17 +60,37 @@ class RectangleDetector(Node):
marker.header.stamp = self.get_clock().now().to_msg()
marker.ns = "rectangle_corners"
marker.id = 0
marker.type = Marker.SPHERE_LIST # 或 Marker.POINTS
marker.type = Marker.SPHERE_LIST
marker.action = Marker.ADD
# 获取8个旋转后的角点
corners = np.asarray(bbox.get_box_points())
center = bbox.center
# 展示角点
for c in corners:
pt = geometry_msgs.msg.Point()
pt.x, pt.y, pt.z = c
marker.points.append(pt)
marker.scale.x = 0.08 # 球半径或点大小
# 展示中心点
center_pt = geometry_msgs.msg.Point()
center_pt.x, center_pt.y, center_pt.z = center
marker.points.append(center_pt)
# 沿中心点到原点方向向外移动10cm
origin = np.array([0.0, 0.0, 0.0])
direction = origin - center
norm = np.linalg.norm(direction)
if norm > 0:
move_vec = direction / norm * 0.46
moved_pt = center + move_vec
else:
moved_pt = center
out_pt = geometry_msgs.msg.Point()
out_pt.x, out_pt.y, out_pt.z = moved_pt
marker.points.append(out_pt)
marker.scale.x = 0.08
marker.scale.y = 0.08
marker.scale.z = 0.08
marker.color.r = 0.0
@ -53,7 +100,6 @@ class RectangleDetector(Node):
marker.lifetime.sec = 1
marker.lifetime.nanosec = 0
self.marker_pub.publish(marker)
# ...existing code...
# ...existing code...
def pointcloud_callback(self, msg):
@ -68,39 +114,47 @@ class RectangleDetector(Node):
return
points = np.array(points_list)
# 发布原始点云到RViz
# 点云预处理
# points = self.filter_points(points)
if len(points) == 0:
self.get_logger().info('滤波后点云为空')
return
self.cloud_pub.publish(msg)
# 转换为Open3D点云对象
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
# 添加体素滤波,滤波分辨率可调
voxel_size = 0.03 # 3cm分辨率
voxel_size = 0.03
pcd = pcd.voxel_down_sample(voxel_size=voxel_size)
# 使用RANSAC拟合矩形框近似为平面+边界筛选)
plane_model, inliers = pcd.segment_plane(
distance_threshold=0.02,
ransac_n=3,
num_iterations=2000
)
inlier_cloud = pcd.select_by_index(inliers)
# bbox = inlier_cloud.get_axis_aligned_bounding_box()
bbox = inlier_cloud.get_oriented_bounding_box() # 修改为贴合实际方向
bbox = inlier_cloud.get_oriented_bounding_box()
extent = bbox.extent
center = bbox.center
self.get_logger().info(f'滤波后bbox中心: {center}, 尺寸: {extent}')
dims = sorted(extent)
if (abs(dims[0] - self.thickness) < 1.0 and
abs(dims[1] - self.width) < 1.0 and
abs(dims[2] - self.length) < 1.0):
self.get_logger().info(f'检测到目标矩形框,位置: {center}, 尺寸: {extent}')
# 检测阈值收紧
if (abs(dims[0] - self.thickness) < 0.1 and
abs(dims[1] - self.width) < 0.2 and
abs(dims[2] - self.length) < 0.2):
bbox = self.smooth_bbox(bbox)
self.get_logger().info(f'检测到目标矩形框,位置: {bbox.center}, 尺寸: {bbox.extent}')
self.publish_marker(bbox)
self.last_bbox = bbox
self.last_time = self.get_clock().now()
else:
self.get_logger().info('未检测到目标矩形框')
# 若上一帧有结果且时间间隔<0.5s,则继续发布上一帧
now = self.get_clock().now()
if self.last_bbox and self.last_time and (now - self.last_time).nanoseconds < 5e8:
self.get_logger().info('本帧未检测到,使用上一帧结果')
self.publish_marker(self.last_bbox)
else:
self.get_logger().info('未检测到目标矩形框')
def main(args=None):
rclpy.init(args=args)