【问题标题】:How can I publish PIL image binary through ROS without OpenCV?如何在没有 OpenCV 的情况下通过 ROS 发布 PIL 图像二进制文件?
【发布时间】:2020-10-15 14:04:44
【问题描述】:

我目前正在尝试编写一个 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 连接发送原始二进制文件?

谢谢

【问题讨论】:

    标签: python numpy python-imaging-library ros rospy


    【解决方案1】:

    确实Mark Setchell's answer 完美运行(在此示例中忽略了 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)
    

    【讨论】:

    • 啊,酷 - 太棒了!感谢您分享更完整的方法。
    • 如果我问是否有一种方法可以用 Python 编写一些东西来等待接收此消息并在它到达时将其保存在一个文件中,我是在碰运气吗?我的意思是只在我的 Mac 上 - 我没有代理或集线器或其他任何运行 ROS 的东西。
    • 我不确定你的问题是否正确......你有一个运行 ROS 的系统并在那里发布图像,现在你想订阅它并将其保存在同一台机器上或至少在同一个网络?那只是一个普通的 ROS 订阅者在听这个主题(在我的例子中是/image)......(在同一个网络中的多台机器上,只需确保指定相同的 ROS_MASTER_URI
    • 不,我没有问最初的问题,我只是给出了一些关于如何在ROS中发送图像的想法的答案。我这里没有 ROS 硬件/系统,也没有关于 ROS 的任何线索。我只是想知道是否可以在我的 Mac 上运行一些 Python 小脚本来等待接收我们设法发送的图像。就这样。这可能是一个愚蠢的问题。我可能需要一个 ROS 主节点和特殊电缆,但我对 ROS 一无所知。谢谢你,如果你知道我怎么能收到我们发送的图片。
    • @MarkSetchell,使用rospy库并编写一个订阅者坐下等待消息,它在接收到消息时使用回调函数进行处理。
    【解决方案2】:

    我对ROS一无所知,但是我经常使用PIL,所以如果其他人知道的更好,请ping我,我会删除这个“最佳猜测” em> 回答。

    所以,您似乎需要从PIL Image 中创建类似this 的东西。所以你需要:

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

    所以,假设你这样做:

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

    你应该可以使用:

    • 您需要解决的问题
    • im.height 来自PIL Image
    • im.width 来自PIL 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 通道,您应该将encoding 更改为"rgba8" 并设置step = im.width * 4

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-23
    • 2019-09-13
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    相关资源
    最近更新 更多