ex) roslaunch 파일에 노드 정보를 추가하는 예시
<launch>
<node name="my_camera_node" pkg="my_package" type="my_camera_node.py" output="screen">
</node>
</launch>
name은 노드의 이름, pkg는 노드가 포함된 패키지 이름, type은 실행할 파이썬 파일 이름, output은 노드 출력 방법을 지정한다.
위 명령어 실행하면 my_launch_file.launch 파일에 정의된 노드가 실행된다.
실행 중인 노드의 출력은 터미널에 출력된다.
ROS에서는 카메라로부터 들어오는 이미지를 토픽으로 publish하고, 이를 다른 노드에서 subscribe하여 이미지를 처리한다. 따라서 영상 출력을 위해서는 이미지를 publish하는 노드에서 해당 이미지 토픽의 이름을 알아야 한다.
ROS에서는 대부분의 카메라 드라이버에서 /image_raw 토픽을 사용한다. 따라서 /image_raw 토픽에서 이미지를 받아올 수 있다. 하지만, ROS 환경에서 사용하는 카메라 드라이버에 따라서 토픽 이름이 다를 수 있으므로, 노드를 실행하여 확인하는 것이 가장 정확한 방법이다.
ROS에서 /image_raw 토픽으로 전송되는 이미지 데이터를 .py에서 가공한 뒤 출력하는 경우, 출력하는 영상의 토픽은 새롭게 생성해야 한다. 이를 위해서는 rospy.Publisher()를 이용해 새로운 토픽을 생성하고, 가공된 이미지 데이터를 해당 토픽으로 publish 해주어야 합니다.
예를 들어, "/image_processed" 라는 새로운 토픽을 생성하여 가공된 이미지 데이터를 publish 해보자.
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
bridge = CvBridge()
# 가공된 영상 토픽을 위한 publisher 생성
processed_image_pub = rospy.Publisher('/image_processed', Image, queue_size=10)
# 원본 영상 토픽에 subscribe
def raw_image_callback(data):
# 원본 영상을 numpy array로 변환
cv_image = bridge.imgmsg_to_cv2(data, "bgr8")
# 영상 가공
processed_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
# 가공된 영상을 ROS 메시지로 변환
processed_image_msg = bridge.cv2_to_imgmsg(processed_image, "mono8")
# 가공된 영상을 publish
processed_image_pub.publish(processed_image_msg)
rospy.init_node('image_processor')
# 원본 영상 토픽에 subscribe
rospy.Subscriber('/image_raw', Image, raw_image_callback)
rospy.spin()
위 코드에서 /image_processed 는 새로 생성한 가공된 이미지 출력 토픽의 이름이며, Image 메시지를 publish 하기 위해 rospy.Publisher()를 이용해 퍼블리셔를 생성하고, rospy.Subscriber()를 이용해 /image_raw 토픽을 구독한다. raw_image_callback() 함수에서는 받아온 raw 이미지 데이터를 OpenCV numpy 배열로 변환한 후 가공하고, 가공된 이미지를 다시 ROS Image 메시지로 변환하여 새로 생성한 토픽에 publish 해준다. rospy.spin()을 호출하여 노드가 종료되지 않도록 한다.
실시간 영상의 경우, ROS에서 제공하는 카메라 노드를 사용하여 카메라의 영상을 받아와서 처리하면 된다. 이때, 이미지 토픽의 이름은 카메라 노드에서 자동으로 지정되며, 이를 직접 변경하는 것은 불가능하다.
따라서, 처리하고자 하는 영상에 대해서는 ROS에서 이미지 토픽을 지정하여 해당 토픽으로부터 영상을 받아와서 처리해야 한다. 이를 위해서는 Python에서 ROS의 이미지 메시지를 받아오는 라이브러리인 cv_bridge를 사용하자. 이를 통해 영상을 받아와서 처리한 후, 새로운 이미지 메시지를 만들어서 새로운 이미지 토픽으로 publish할 수 있다. 이때, 이미지 토픽의 이름은 사용자가 원하는대로 지정할 수 있다.
실시간 영상의 경우, OpenCV의 VideoCapture() 함수를 사용하여 비디오 스트림을 가져와야 한다. VideoCapture() 함수를 사용하면 영상을 프레임별로 처리할 수 있다.
이후, cv2.imshow() 함수를 사용하여 프레임을 화면에 출력할 수 있다.
그러나, 이 방법은 이미지를 화면에 출력할 뿐만 아니라, 이미지를 처리하기 전의 원본 이미지를 가지고 있기 때문에, 처리된 이미지의 토픽을 지정하는 것은 어렵다.
따라서, 원본 이미지를 처리하는 과정에서 바로 원하는 토픽으로 출력하는 방법을 사용해야 한다. 이를 위해서는 ROS의 이미지 메시지 형식으로 이미지 데이터를 변환하고, 변환된 이미지를 원하는 토픽으로 발행(publish)해야 한다. 이 방법을 사용하면 처리된 이미지를 바로 원하는 토픽으로 출력할 수 있다.
변환된 이미지를 원하는 토픽으로 발행하기 위해서는 먼저 해당 토픽으로 메시지를 발행할 수 있는 ROS Publisher를 생성해야 한다. 이후 cv_bridge를 사용하여 이미지를 ROS 메시지 형태로 변환한 뒤, 생성한 Publisher를 이용하여 메시지를 발행한다.
예시 코드
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
# ROS 노드 초기화
rospy.init_node('image_publisher', anonymous=True)
# 원하는 토픽명으로 Publisher 생성
pub = rospy.Publisher('my_topic', Image, queue_size=10)
# cv_bridge 초기화
bridge = CvBridge()
# 이미지 로드
img = cv2.imread('my_image.jpg')
# 이미지를 ROS 메시지 형태로 변환
img_msg = bridge.cv2_to_imgmsg(img, "bgr8")
# 변환된 이미지 메시지 발행
pub.publish(img_msg)
# ROS 종료
rospy.on_shutdown(lambda: pub.unregister())
rospy.spin()입력하세요
위 코드에서 my_topic 부분을 원하는 토픽명으로 변경하고, 발행하고자 하는 이미지를 로드한 뒤 cv2_to_imgmsg() 함수를 사용하여 ROS 메시지 형태로 변환한다. 이후 Publisher를 통해 메시지를 발행한다. 코드 실행 중 rospy.spin()은 ROS에서 메시지를 수신하고 발행하는 데 필요한 메인 루프를 유지하기 위한 함수이다. rospy.on_shutdown()은 ROS 노드가 종료될 때 실행되는 함수를 등록하는데, 이 예시에서는 Publisher를 등록 해제하도록 설정했다.