How to subscribe and publish images in ROS
Question:
I am trying to subscribe to the “/camera/image_color” topic which is data from my camera. I then want to do some voodoo on these images in opencv and publish them at a specific frequency. So that I can subscribe to them with another node.
I have sofar tried the below code, and many many variations thereof. At this point the code is doing nothing. No images are being published to the “/imagetimer” topic. I get an output “Timing images” then nothing happens further.
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import os
import numpy as np
class Nodo(object):
def __init__(self):
# Params
self.image = None
self.br = CvBridge()
# Node cycle rate (in Hz).
self.loop_rate = rospy.Rate(1)
# Publishers
self.pub = rospy.Publisher('imagetimer', Image,queue_size=10)
# Subscribers
rospy.Subscriber("/camera/image_color",Image,self.callback)
def callback(self, msg):
self.image = self.br.imgmsg_to_cv2(msg)
def start(self):
rospy.loginfo("Timing images")
rospy.spin()
br = CvBridge()
while not rospy.is_shutdown():
rospy.loginfo('publishing image')
#br = CvBridge()
self.pub.publish(br.cv2_to_imgmsg(self.image))
rate.sleep()
if __name__ == '__main__':
rospy.init_node("imagetimer111", anonymous=True)
my_node = Nodo()
my_node.start()
Answers:
In my case, I found that the image topic had compressed images. Please verify if that is the case for you.
I used the following code to read from .bag files. If you find that you have compressed images coming in on your ROS topic, you can use parts of this code to perform the conversion
bag = rosbag.Bag(os.path.join(path_to_bags, bag_list[index]))
for topic, msg, t in bag.read_messages(topics=['/conti115/image_raw/compressed']):
try:
img = bridge.compressed_imgmsg_to_cv2(msg)
except CvBridgeError, e:
print e
txt = str(datetime.datetime.fromtimestamp(t.to_sec()))
cv2.rectangle(img, (0, 0), (500, 40), (0,0,0), -1)
cv2.putText(img, txt, (0, 30), 1, 2, (255, 255, 255), 2)
cv2.imshow("win",img)
wtr.write(img)
if cv2.waitKey(5)==27:
cv2.destroyAllWindows()
break
bag.close()
Once you run rospy.spin()
the code doesn’t go forward. In rospy as soon as you have the rospy.Subsriber()
line it spins off another thread for the callback. A rospy.spin()
essentially keeps the node alive so the callbacks and keep chugging.
Here you are using a while loop for keeping the node alive, so shouldn’t need rospy.spin()
.
This version should work:
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import os
import numpy as np
class Nodo(object):
def __init__(self):
# Params
self.image = None
self.br = CvBridge()
# Node cycle rate (in Hz).
self.loop_rate = rospy.Rate(1)
# Publishers
self.pub = rospy.Publisher('imagetimer', Image,queue_size=10)
# Subscribers
rospy.Subscriber("/camera/image_color",Image,self.callback)
def callback(self, msg):
rospy.loginfo('Image received...')
self.image = self.br.imgmsg_to_cv2(msg)
def start(self):
rospy.loginfo("Timing images")
#rospy.spin()
while not rospy.is_shutdown():
rospy.loginfo('publishing image')
#br = CvBridge()
if self.image is not None:
self.pub.publish(self.br.cv2_to_imgmsg(self.image))
self.loop_rate.sleep()
if __name__ == '__main__':
rospy.init_node("imagetimer111", anonymous=True)
my_node = Nodo()
my_node.start()
I am trying to subscribe to the “/camera/image_color” topic which is data from my camera. I then want to do some voodoo on these images in opencv and publish them at a specific frequency. So that I can subscribe to them with another node.
I have sofar tried the below code, and many many variations thereof. At this point the code is doing nothing. No images are being published to the “/imagetimer” topic. I get an output “Timing images” then nothing happens further.
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import os
import numpy as np
class Nodo(object):
def __init__(self):
# Params
self.image = None
self.br = CvBridge()
# Node cycle rate (in Hz).
self.loop_rate = rospy.Rate(1)
# Publishers
self.pub = rospy.Publisher('imagetimer', Image,queue_size=10)
# Subscribers
rospy.Subscriber("/camera/image_color",Image,self.callback)
def callback(self, msg):
self.image = self.br.imgmsg_to_cv2(msg)
def start(self):
rospy.loginfo("Timing images")
rospy.spin()
br = CvBridge()
while not rospy.is_shutdown():
rospy.loginfo('publishing image')
#br = CvBridge()
self.pub.publish(br.cv2_to_imgmsg(self.image))
rate.sleep()
if __name__ == '__main__':
rospy.init_node("imagetimer111", anonymous=True)
my_node = Nodo()
my_node.start()
In my case, I found that the image topic had compressed images. Please verify if that is the case for you.
I used the following code to read from .bag files. If you find that you have compressed images coming in on your ROS topic, you can use parts of this code to perform the conversion
bag = rosbag.Bag(os.path.join(path_to_bags, bag_list[index]))
for topic, msg, t in bag.read_messages(topics=['/conti115/image_raw/compressed']):
try:
img = bridge.compressed_imgmsg_to_cv2(msg)
except CvBridgeError, e:
print e
txt = str(datetime.datetime.fromtimestamp(t.to_sec()))
cv2.rectangle(img, (0, 0), (500, 40), (0,0,0), -1)
cv2.putText(img, txt, (0, 30), 1, 2, (255, 255, 255), 2)
cv2.imshow("win",img)
wtr.write(img)
if cv2.waitKey(5)==27:
cv2.destroyAllWindows()
break
bag.close()
Once you run rospy.spin()
the code doesn’t go forward. In rospy as soon as you have the rospy.Subsriber()
line it spins off another thread for the callback. A rospy.spin()
essentially keeps the node alive so the callbacks and keep chugging.
Here you are using a while loop for keeping the node alive, so shouldn’t need rospy.spin()
.
This version should work:
import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
import os
import numpy as np
class Nodo(object):
def __init__(self):
# Params
self.image = None
self.br = CvBridge()
# Node cycle rate (in Hz).
self.loop_rate = rospy.Rate(1)
# Publishers
self.pub = rospy.Publisher('imagetimer', Image,queue_size=10)
# Subscribers
rospy.Subscriber("/camera/image_color",Image,self.callback)
def callback(self, msg):
rospy.loginfo('Image received...')
self.image = self.br.imgmsg_to_cv2(msg)
def start(self):
rospy.loginfo("Timing images")
#rospy.spin()
while not rospy.is_shutdown():
rospy.loginfo('publishing image')
#br = CvBridge()
if self.image is not None:
self.pub.publish(self.br.cv2_to_imgmsg(self.image))
self.loop_rate.sleep()
if __name__ == '__main__':
rospy.init_node("imagetimer111", anonymous=True)
my_node = Nodo()
my_node.start()