ROS2(humble + 22.04) depth camera
2024. 12. 17. 12:56ㆍROS2/기초
전체 흐름
- 뎁스 이미지 수신: ROS 2에서 뎁스 카메라의 depth topic 데이터를 수신.
- 2D 픽셀 → 3D 좌표 변환: 카메라 매트릭스(내부 파라미터)를 사용하여 픽셀 좌표와 뎁스 값을 3D 좌표로 변환.
- 3D 그래프 시각화: 변환된 3D 좌표를 Matplotlib, Open3D 또는 다른 라이브러리로 시각화.
카메라 파라미터
카메라 매트릭스를 통해 2D 픽셀 좌표를 3D 공간 좌표로 변환합니다. 이때 중요한 파라미터는:
- fx, fy: 카메라의 초점 거리 (focal length, x/y 방향).
- cx, cy: 이미지의 중심 좌표.
이 값은 카메라의 intrinsic 파라미터에서 가져올 수 있습니다. (RealSense SDK 및 ROS 토픽에서 제공).
코드 구현
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
class DepthTo3DGraph(Node):
def __init__(self):
super().__init__('depth_to_3d_graph')
# Depth 이미지 구독
self.subscription = self.create_subscription(
Image,
'/intel_realsense_r200_depth/depth/image_raw', # 뎁스 이미지 토픽
self.depth_callback,
10
)
self.bridge = CvBridge()
self.fx = 525.0 # 카메라의 focal length (x)
self.fy = 525.0 # 카메라의 focal length (y)
self.cx = 319.5 # 이미지 중심 (x)
self.cy = 239.5 # 이미지 중심 (y)
self.get_logger().info("Depth to 3D Graph Node started.")
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111, projection='3d')
def depth_callback(self, msg):
try:
# ROS Image를 OpenCV 뎁스 이미지로 변환
depth_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding='passthrough')
depth_image = np.array(depth_image, dtype=np.float32)
# 이미지의 모든 픽셀을 3D 좌표로 변환
height, width = depth_image.shape
x_coords, y_coords = np.meshgrid(np.arange(width), np.arange(height))
# 3D 좌표 계산
z = depth_image / 1000.0 # 뎁스 값 (단위: m, RealSense는 mm 단위)
x = (x_coords - self.cx) * z / self.fx
y = (y_coords - self.cy) * z / self.fy
# 유효한 값만 필터링 (z > 0)
mask = z > 0
x = x[mask]
y = y[mask]
z = z[mask]
# 3D 그래프 그리기
self.ax.clear()
self.ax.scatter(x, y, z, c=z, cmap='jet', s=1) # 3D 점들 시각화
self.ax.set_xlabel('X (m)')
self.ax.set_ylabel('Y (m)')
self.ax.set_zlabel('Z (m)')
self.ax.set_title("3D Point Cloud from Depth Camera")
plt.draw()
plt.pause(0.01) # 실시간 업데이트
except Exception as e:
self.get_logger().error(f"Error processing depth image: {e}")
def main(args=None):
rclpy.init(args=args)
node = DepthTo3DGraph()
try:
plt.ion() # Matplotlib 인터랙티브 모드
rclpy.spin(node)
except KeyboardInterrupt:
pass
node.destroy_node()
rclpy.shutdown()
plt.ioff()
plt.show()
if __name__ == '__main__':
main()
코드 설명
- 카메라 파라미터:
- fx, fy: 초점 거리. (RealSense R200 기본값: 525.0)
- cx, cy: 이미지 중심 좌표.
- 2D → 3D 변환:
수식:x=(u−cx)⋅zfx,y=(v−cy)⋅zfy,z=depth valuex = \frac{(u - c_x) \cdot z}{f_x}, \quad y = \frac{(v - c_y) \cdot z}{f_y}, \quad z = \text{depth\ value}- u, v: 이미지 픽셀 좌표.
- z: 뎁스 값.
- 3D 점 시각화:
- Matplotlib의 scatter를 사용해 점을 3D 그래프에 표시.
- **c=z**를 사용해 뎁스 값에 따라 색상을 다르게 표시.
- 실시간 업데이트:
- plt.draw()와 plt.pause(0.01)를 사용해 실시간으로 그래프를 업데이트.
결과
- 뎁스 이미지의 각 픽셀이 3D 좌표로 변환되어 3D 점 그래프로 나타난다.
- 뎁스 값에 따라 점의 색상이 변경.
확장 가능성
- PointCloud 메시지로 변환:
ROS 2의 sensor_msgs/PointCloud2로 퍼블리시하여 다른 노드에서 사용. - Open3D를 사용해 실시간 3D 시각화 성능 개선.
- 3D 점 클라우드 저장: PCD 또는 XYZ 포맷으로 저장하여 분석할 수 있음.
'ROS2 > 기초' 카테고리의 다른 글
Gazebo에서 velodyne 3d Lidar 써보기 (0) | 2024.12.23 |
---|---|
ubuntu 24.04 ssh 설정 + docker 설정 (0) | 2024.12.06 |
ROS2 - topic(c++) (0) | 2024.10.21 |
ROS2 4일차(2) Maze World (0) | 2024.09.24 |
ROS2 4일차(1) Maze World (0) | 2024.09.24 |