2016-11-25 155 views
1

我正在与Windows和sdk的kinect v1传感器的项目。我们的目标是通过ros发送来自kinect的彩色图像,我不知道如何处理这个问题。现在我正在使用sensor_msgs/Image消息来发布RGB值。这是我到目前为止的代码:rosserial发布sensor_msgs /从窗口的图像

img.header.stamp = nh->now(); 
    img.header.frame_id = "kinect1_ref"; 
    img.height = height; 
    img.width = width;   
    img.encoding = "rgb8"; 
    img.is_bigendian = false; 
    img.step = width*3; 

    BYTE* start = (BYTE*) lockedRect.pBits; 
    img.data = new uint8_t[width*3*height]; 



    long it; 
    for (int y = 0; y < height; ++y) { 
     for (int x = 0; x < width; ++x) { 
      const BYTE* curr = start + (x + width*y)*4; 
      for(int n=0; n<3; n++){ 
       it = y*width*3 + x*3 + n; 
       img.data[it] = (uint8_t) curr[2-n]; 
      } 
     } 
    } 
    pub->publish(&img); 

在代码中,IMG是sensor_msgs /图像,并lockedRect.pBits是一个指针的kinect的图像的第一个字节。据我所知,来自kinect的图像按照从上到下的从左到右的顺序逐行存储,每个像素由代表填充字节然后是R,G和B的4个连续字节表示。

其实我很能寄这封信给罗斯,但是当我试图用对visualizate它,我得到以下错误:

错误加载图片:OGRE EXCEPTION。流大小与图像中的计算图像大小不匹配。

我非常喜欢这个,我设置的尺寸是正确的,考虑到RGB的3个通道。从BYTEuint8_t的转换应该是微不足道的,因为它们都是无符号字符。

PD:我知道我可以使用openni_launch从ubuntu和ros中查看kinect数据,但是由于语音识别引擎,我需要在这种情况下使用windows。

PD2:通常用于在ros中发布图像的cv_bridge不包含在rosserial库中。因此,我必须从头开始构建图像消息(可能有另一种方法?)

任何帮助将真正appreaciated,提前谢谢!

编辑:通过rosserial窗户生成的类别sensor_msgs /图像信息是只包含这个代码:

class Image : public ros::Msg{ 
public: 
    std_msgs::Header header; 
    uint32_t height; 
    uint32_t width; 
    char * encoding; 
    uint8_t is_bigendian; 
    uint32_t step; 
    uint8_t data_length; 
    uint8_t st_data; 
    uint8_t * data; 
    virtual void serialize(unsigned char *outbuffer); 
    virtual void deserialize(unsigned char *inbuffer);} 

两种方法进行序列化和反序列化不写到这里,但我居然不知道他们如何工作。

回答

0

我想知道这是如何编译给你的。 img.datastd::vector<uint8_t>。随着中说,试试这个:

img.header.stamp = nh->now(); 
img.header.frame_id = "kinect1_ref"; 
img.height = height; 
img.width = width;   
img.encoding = "rgb8"; 
img.is_bigendian = false; 
img.step = width * 3; 

BYTE* start = (BYTE*) lockedRect.pBits; 
img.data.resize(img.step * height); 

long it; 
for (int y = 0; y < height; ++y) { 
    for (int x = 0; x < width; ++x) { 
     const BYTE* curr = start + (x + width*y)*4; 
     for(int n=0; n<3; n++){ 
      it = y*width*3 + x*3 + n; 
      img.data[it] = (uint8_t) curr[2-n]; 
     } 
    } 
} 
pub->publish(&img); 

更新

,我发现关于rosserial_windows限制使用的协议这一信息。虽然,您正在指定高度和宽度以及步长,但序列化与这些消息变量无关。我似乎还必须在data_lendth中指定数组的长度。但这是问题。由于某些奇怪的原因,最大阵列长度限制为uint8_t

任何数组类型T []的数组长度将需要设置变量T_length。这意味着在不更改协议的情况下不能超出uint8_t限制。

一个解决方案,但痛苦和缓慢的是将图像分割成255字节的自定义消息和索引它们。您必须将图像数据放在接收端,并从数据创建sensor_msgs :: Image并发布。

+0

嗨,谢谢你的回答!它实际上是以这种方式在ros中定义的。但问题是,当pkg rosserial为windows建立库时,它只需要消息的骨架类。因此,在我的“sensor_msgs/Image”类中,数据数组定义为:uint8_t * data。这就是为什么我必须在我自己的代码中初始化数组。如果我不这样做,它不会编译。 –

+0

我明白了。看起来序列化缺少一些维度。我想设置的步骤,高度和宽度不足以正确序列化。我看到这里有两个变量'data_length'和'st_data'。这可能是问题。 – cassinaj

+0

我发现了关于[rosserial_windows的限制](http://wiki.ros.org/rosserial/Overview/Limitations#Arrays)中使用的协议的信息。虽然,您正在指定高度和宽度以及步长,但序列化与这些消息变量无关。我似乎还必须在'data_lendth'中指定数组的长度。但这是问题。由于某些奇怪的原因,最大数组长度限制为'uint8_t'。 – cassinaj

0

首先,感谢cassinaj,我认为解决方案将是他提出的答案。不过,我会添加一些我在同样情况下为人们找到的信息。

在rosserial阵列的限制是由uint8_t这在大多数所述ROS分布的最大的255个字节中给出。然而,这个问题已经在这个thread中被评论过,其中建议将该值增加到uint32_t。变化was done in Jade devel。因此,如果您从Jade中的rosserial生成了ros_lib库,则数据的长度应为uint32_t。这是现在的图像信息生成的代码:

class Image : public ros::Msg 
    { 
    public: 
    std_msgs::Header header; 
    uint32_t height; 
    uint32_t width; 
    const char* encoding; 
    uint8_t is_bigendian; 
    uint32_t step; 
    uint32_t data_length; 
    uint8_t st_data; 
    uint8_t * data; 
    Image(): 
    header(), 
    height(0), 
    width(0), 
    encoding(""), 
    is_bigendian(0), 
    step(0), 
    data_length(0), data(NULL) 
{ 
} 
virtual int serialize(unsigned char *outbuffer) const 
virtual int deserialize(unsigned char *inbuffer) 

我期待得到的一切现在的工作,但另一个问题出现了。尽管阵列的长度可以是很高的值,但是rosserial消息的缓冲区仍然被限制在一个较低的值。我想这是协议本身是有限的。然后,我无法发送整个480x640xRGB的图像信息,但我可以发送图像的一部分(8x8xRGB),就像我测试的一样。这终于奏效了,我在rviz中形象化了图像,没有任何问题。

因此,正如cassinaj提出的,一种解决方案是将所有数据分成部分,然后将它们全部放在接收端。这应该是有效的,尽管听起来真的很痛苦(如果我将图像分成8x8部分,那么对于单个图像来说,大概是4800条消息!)。

出于这个原因,我想使用win_ros(适用于Windows ROS),以便通过ROS本身发送从Kinect的所有数据。可惜的是,rosserial有这些限制,因为它很容易使用和实施。

如果有人有什么要补充的,或者我错过了什么,请告诉我。任何帮助真的appreaciated!