我正在开发一个带有windows和kinect v1传感器的sdk的项目。目标是将kinect中的彩色图像发送到ros, using rosserial.
我不确切知道如何处理这件事。现在我正在使用sensor_msgs/Image消息发布RGB值。这是我到目前为止的代码:
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 / Image, lockedRect.pBits 是指向kinect图像第一个字节的指针。据我所知,来自kinect的图像按行从上到下依次存储,每个像素由4个连续字节表示,表示填充字节,然后是R,G和B.
我实际上能够将此发送给ros,但是当我尝试使用它时,我会收到以下错误:
加载图片时出错:OGRE EXCEPTION。流大小与图像中计算的图像大小不匹配。
我非常喜欢这个,我设置的大小是正确的,考虑到RGB的3个通道。从 BYTE 到 uint8_t 的转换应该是微不足道的,因为它们都是无符号字符。
PD:我知道我可以使用openni_launch来显示来自ubuntu和ros的kinect数据,但由于语音识别引擎,我需要在这种情况下使用windows。PD2:cv_bridge,通常用于在ros中发布图像,不包含在rosserial库中。因此,我必须从头开始构建图像消息(可能还有另一种方式?)
任何帮助都会得到真正的帮助,请提前谢谢!
编辑: rosserial for windows生成的sensor_msgs / Image消息类仅包含以下代码:
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 :(得分:0)
我想知道这是如何编译的。 img.data
是std::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并发布。
答案 1 :(得分:0)
首先,感谢cassinaj,我认为解决方案将是他提出的答案。我将添加一些我在同样情况下为人们找到的信息。
rosserial中数组的限制由uint8_t
给出,在大多数ros分布中最多为255个字节。但是,此问题已在此thread中进行了评论,建议将此值增加到uint32_t
。变化was done in Jade devel。因此,如果您从Jade中的rosserial生成 ros_lib 库,则数据的长度应为uint32_t
。现在,这是Image消息的生成代码:
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(ros for windows),以便通过ros本身发送来自kinect的所有数据。遗憾的是,rosserial具有这些局限性,因为它非常易于使用和实施。
如果有人要添加任何其他内容,或者我遗失了某些内容,请告知我们。任何帮助都是真正的帮助!