没有OpenCV的情况下如何通过ROS发布PIL图像二进制文件?

问题描述

我目前正在尝试编写ROS发布者/订阅者设置,该设置可传递由PIL打开的图像二进制文件。由于操作限制,我不想使用OpenCV,我想知道是否可以使用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连接发送原始二进制文件的转换方法/不同的消息类型?

谢谢

解决方法

我对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

,

实际上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)