2

我目前正在尝试编写一个 ROS Publisher/Subscriber 设置来传递 PIL 打开的图像二进制文件。由于操作限制,我不想使用 OpenCV,我想知道是否有办法这样做。这是我当前的代码:

#!/usr/bin/env python
import rospy
from PIL import Image
from sensor_msgs.msg import Image as sensorImage
from rospy.numpy_msg import numpy_msg
import numpy

def talker():
    pub = rospy.Publisher('image_stream', numpy_msg(sensorImage), queue_size=10)
    rospy.init_node('image_publisher', anonymous=False)
    rate = rospy.Rate(0.5)
    while not rospy.is_shutdown():
        im = numpy.array(Image.open('test.jpg'))
        pub.publish(im)
        rate.sleep()

if __name__ == '__main__'
    try:
        talker()
    except ROSInterruptException:
        pass

在 pub.publish(im) 尝试抛出:

TypeError: Invalid number of arguments, args should be ['header', 'height', 'width', 'encoding', 'is_bigendian', 'step', 'data'] args are (array([[[***array data here***]]], dtype=uint8),)

如何将图像转换为正确的形式,或者是否有一种转换方法/不同的消息类型支持仅通过 ROS 连接发送原始二进制文件?

谢谢

4

2 回答 2

2

确实, Mark Setchell 的答案非常有效(在此示例中忽略了 alpha 通道):

#!/usr/bin/env python
import rospy
import urllib2  # for downloading an example image
from PIL import Image
from sensor_msgs.msg import Image as SensorImage
import numpy as np

if __name__ == '__main__':
    pub = rospy.Publisher('/image', SensorImage, queue_size=10)

    rospy.init_node('image_publisher')

    im = Image.open(urllib2.urlopen('https://cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon.png'))
    im = im.convert('RGB')

    msg = SensorImage()
    msg.header.stamp = rospy.Time.now()
    msg.height = im.height
    msg.width = im.width
    msg.encoding = "rgb8"
    msg.is_bigendian = False
    msg.step = 3 * im.width
    msg.data = np.array(im).tobytes()
    pub.publish(msg)
于 2020-10-23T14:40:06.370 回答
1

我对ROS一无所知,但是我经常使用PIL,所以如果其他人更了解,请ping我,我将删除这个“最佳猜测”答案。

因此,您似乎需要PIL Image. 所以你需要:

  • '标题',
  • '高度',
  • '宽度',
  • '编码',
  • 'is_bigendian',
  • '步',
  • '数据'

所以,假设你这样做:

im = Image.open('test.jpg')

你应该能够使用:

  • 你需要解决的问题
  • im.heightPIL Image
  • im.widthPIL Image
  • 大概const std::string RGB8 = "rgb8"
  • 可能无关紧要,因为数据是 8 位的
  • 可能是im.width * 3因为它是每像素 RGB 3 个字节
  • np.array(im).tobytes()

在任何人记下这个答案之前,没有人说答案必须是完整的 - 他们只能“希望有帮助”

请注意,如果您的输入图像是 PNG 格式,您应该检查im.mode它是否"P"(即调色板模式)立即运行:

im = im.convert('RGB')

确保它是 3 通道 RGB。

请注意,如果您的输入图像是 PNG 格式并包含 alpha 通道,您应该将encodingto"rgba8"和 set更改为step = im.width * 4

于 2020-10-15T15:57:50.120 回答