@小鱼 完整代码:
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
from flask import Flask, Response
import io
import threading
import argparse
# 初始化Flask应用
app = Flask(__name__)
# 创建一个全局变量来存储图像数据
current_image = None
# 创建ROS2节点类
class ImageSubscriber(Node):
def __init__(self, topic_name):
super().__init__('image_subscriber')
self.subscription = self.create_subscription(
Image,
topic_name,
self.image_callback,
10)
self.subscription # 防止订阅被自动销毁
self.bridge = CvBridge()
def image_callback(self, msg):
global current_image
cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8")
# 将图像转换为JPEG格式
_, buffer = cv2.imencode('.jpg', cv_image)
current_image = buffer.tobytes()
# 生成器函数,不断发送图像
def generate():
while True:
if current_image is not None:
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + current_image + b'\r\n')
else:
yield (b'--frame\r\n'
b'Content-Type: text/plain\r\n\r\nNo image available\r\n')
@app.route('/video_stream')
def video_stream():
return Response(generate(),
mimetype='multipart/x-mixed-replace; boundary=frame')
def run_ros_node(topic_name):
rclpy.init()
image_subscriber = ImageSubscriber(topic_name)
rclpy.spin(image_subscriber)
# 清理和关闭ROS2节点
image_subscriber.destroy_node()
rclpy.shutdown()
def main(args=None):
parser = argparse.ArgumentParser(description="Subscribe to a ROS2 image topic and serve it as a video stream.")
parser.add_argument('topic_name', type=str, help="The name of the ROS2 topic to subscribe to.")
args = parser.parse_args()
# 创建线程运行ROS2节点
ros_thread = threading.Thread(target=run_ros_node, args=(args.topic_name,))
ros_thread.start()
# 启动Flask HTTP服务器
try:
app.run(host='0.0.0.0', port=5000, threaded=True)
except KeyboardInterrupt:
pass
finally:
# 确保ROS线程可以优雅退出
ros_thread.join()
if __name__ == '__main__':
main()