cmvr-es/python/vision_servo/get_chessboard_position.py

121 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
实时检测红色圆点并获取 3D 坐标 (m)。
深度图对齐到彩色图。
"""
import cv2
import numpy as np
import pyrealsense2 as rs
import sys
import time
from pathlib import Path
# 把.so所在目录加入 Python 路径
sys.path.append("/home/lgv/cmvr/cmvr-es/cmake-build-debug/example")
# 导入机器人控制模块
from robot_wrapper import Robot
REPO_ROOT = Path(__file__).resolve().parents[2]
ROBOT_CONFIG = str(REPO_ROOT / "cmvr-es/config/cmvr_es.pb.txt")
def init_realsense():
"""初始化 RealSense 管道并返回 pipeline 和 align 对象"""
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 1280, 720, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 1280, 720, rs.format.bgr8, 30)
profile = pipeline.start(config)
align = rs.align(rs.stream.color)
return pipeline, align
def get_closest_red_point(pipeline, align, vis_path=None, warmup=30,
hough_params=None):
"""
获取最近红色圆点的 3D 坐标。
返回 (x, y, z) 或 None如果没检测到
"""
if hough_params is None:
hough_params = dict(dp=1.2, minDist=20,
param1=50, param2=15,
minRadius=5, maxRadius=50)
# 丢掉前几帧,让相机稳定
for _ in range(warmup):
pipeline.wait_for_frames()
frames = pipeline.wait_for_frames()
aligned_frames = align.process(frames)
depth_frame = aligned_frames.get_depth_frame()
color_frame = aligned_frames.get_color_frame()
if not depth_frame or not color_frame:
return None
depth_image = np.asanyarray(depth_frame.get_data())
color_image = np.asanyarray(color_frame.get_data())
depth_intrin = depth_frame.profile.as_video_stream_profile().intrinsics
# 转换到 HSV 并提取红色区域
hsv = cv2.cvtColor(color_image, cv2.COLOR_BGR2HSV)
lower_red1, upper_red1 = np.array([0, 100, 100]), np.array([10, 255, 255])
lower_red2, upper_red2 = np.array([160, 100, 100]), np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower_red1, upper_red1) | cv2.inRange(hsv, lower_red2, upper_red2)
# 平滑处理再检测圆
mask_blur = cv2.GaussianBlur(mask, (9, 9), 2)
circles = cv2.HoughCircles(mask_blur, cv2.HOUGH_GRADIENT, **hough_params)
closest_point, min_depth = None, float('inf')
if circles is not None:
circles = np.uint16(np.around(circles))
for u, v, r in circles[0, :]:
depth = depth_frame.get_distance(int(u), int(v))
if 0 < depth < min_depth:
min_depth = depth
closest_point = rs.rs2_deproject_pixel_to_point(depth_intrin, [int(u), int(v)], depth)
if vis_path:
cv2.circle(color_image, (u, v), r, (0, 255, 0), 2)
cv2.circle(color_image, (u, v), 6, (0, 0, 255), -1)
if vis_path and closest_point is not None:
cv2.imwrite(vis_path, color_image)
return closest_point
def main(serial="243122075614", avg_window=3, loop=True):
pipeline, align = init_realsense()
# robot = Robot(ROBOT_CONFIG, "hc01")
try:
while True:
point_3d = get_closest_red_point(pipeline, align, vis_path="red_point.png")
if point_3d:
print("Closest red 3D point:", np.round(point_3d, 4))
else:
print("未检测到红点")
if not loop:
break
key = cv2.waitKey(1)
if key == 27: # ESC 键退出
break
except Exception as e:
print("Error:", e)
finally:
pipeline.stop()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()