Сохранение и добавление прошлых облаков точек из kinect с помощью библиотеки облаков точек и ROS

Я пытаюсь построить локальную карту, добавляя облака точек из Kinect, используя итеративную ближайшую точку из библиотеки облаков точек и ROS Hydro в Ubuntu 12.04. Однако я не могу складывать последовательные облака точек вместе для обновления карты. Проблема в том, что выровненное облако точек добавляется только с исходным облаком точек для этих текущих кадров. У меня проблемы с сохранением предыдущих облаков точек. Как видно из кода, я обновляю карту с помощью

Final+=*cloud_in;

Однако каждый раз вычисляется новый Final, поэтому я теряю старое значение Final. Мне нужно сохранить это. Я новичок в C ++ и ROS, поэтому буду очень признателен за помощь в этом вопросе.

Ниже приведен код:

ros::Publisher _pub;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_in (new pcl::PointCloud<pcl::PointXYZRGB>);

void
cloud_cb2 (const sensor_msgs::PointCloud2ConstPtr& next_input)
{
  pcl::fromROSMsg (*next_input, *cloud_in);
  //remove NAN points from the cloud
  std::vector<int> indices;
  pcl::removeNaNFromPointCloud(*cloud_in,*cloud_in, indices);
// Convert the sensor_msgs/PointCloud2 data to pcl::PointCloud
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud2_in (new pcl::PointCloud<pcl::PointXYZRGB>);
  pcl::fromROSMsg (*next_input, *cloud2_in);
  //remove NAN points
  std::vector<int> indices2;
  pcl::removeNaNFromPointCloud(*cloud2_in,*cloud2_in, indices2);

  pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;
  icp.setInputSource(cloud2_in);
  icp.setInputTarget(cloud_in);
  pcl::PointCloud<pcl::PointXYZRGB> Final;
  icp.align(Final);
  std::cout << "has converged:" << icp.hasConverged() << " score: " <<
  icp.getFitnessScore() << std::endl;
  std::cout << icp.getFinalTransformation() << std::endl;
  Final+=*cloud_in;

 // Convert the pcl::PointCloud to sensor_msgs/PointCloud2
  sensor_msgs::PointCloud2 output;
  pcl::toROSMsg( Final, output );
  // Publish the map
  _pub.publish(output);
}

int main (int argc, char** argv)
{
  ros::init (argc, argv, "my_pcl_tutorial");
  ros::NodeHandle nh;

  // ROS subscriber for /camera/depth_registered/points
  ros::Subscriber sub = nh.subscribe(
                    "/camera/depth_registered/points",
                    2,
                    cloud_cb2
                    );

  // Create ROS publisher for transformed pointcloud
  _pub = nh.advertise<sensor_msgs::PointCloud2>(
                           "output",
                           1
                           );
  // Spin
  ros::spin ();
}

person asidd    schedule 02.03.2015    source источник


Ответы (1)


Я думаю, вы делаете это неправильно ... Я имею в виду, идея cloud_cb2 - быть обратным вызовом (по крайней мере, это обычная вещь в примерах, где они используют похожее имя и определение), поэтому идея состоит в том, что каждый раз он входит в эту функцию, он дает вам новое облако, которое вы должны интегрировать в свое предыдущее облако ...

Я полагаю, что, делая pcl::fromROSMsg (*next_input, *cloud2_in);, вы заставляете программу предоставлять вам новое облако, но это не должно быть так, как я говорил вам ранее.

Затем, чтобы ответить на ваш вопрос:

icp.align(Final);

Если вы читаете руководство из PCL здесь, оно сообщает вам, что эта функция получает в качестве входных данных переменная облака точек, которая будет содержать результат icp.

Также результатом будет выравнивание (или попытка)

icp.setInputSource(cloud2_in);

соответствовать

icp.setInputTarget(cloud_in);

Итак, вы перезаписываете Final, выравнивая 2 новых облака, а затем добавляете точки cloud_in, которые уже находятся в облаке точек.

Я рекомендую вам еще раз проверить свой рабочий процесс, он должен быть примерно таким

ros::Publisher _pub;
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_in (new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr Final (new pcl::PointCloud<pcl::PointXYZRGB>);

void
cloud_cb2 (const sensor_msgs::PointCloud2ConstPtr& next_input)
{
  pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp_cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
  pcl::fromROSMsg (*next_input, *cloud_in);
  //remove NAN points from the cloud
  std::vector<int> indices;
  pcl::removeNaNFromPointCloud(*cloud_in,*cloud_in, indices);

  pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;
  icp.setInputSource(cloud_in);
  icp.setInputTarget(Final);
  pcl::PointCloud<pcl::PointXYZRGB> Final;
  icp.align(tmp_cloud);
  std::cout << "has converged:" << icp.hasConverged() << " score: " <<
  icp.getFitnessScore() << std::endl;
  std::cout << icp.getFinalTransformation() << std::endl;
  Final = tmp_cloud;

 // Convert the pcl::PointCloud to sensor_msgs/PointCloud2
  sensor_msgs::PointCloud2 output;
  pcl::toROSMsg( Final, output );
  // Publish the map
  _pub.publish(output);
}

int main (int argc, char** argv)
{
  ros::init (argc, argv, "my_pcl_tutorial");
  ros::NodeHandle nh;

  // ROS subscriber for /camera/depth_registered/points
  ros::Subscriber sub = nh.subscribe(
                    "/camera/depth_registered/points",
                    2,
                    cloud_cb2
                    );

  // Create ROS publisher for transformed pointcloud
  _pub = nh.advertise<sensor_msgs::PointCloud2>(
                           "output",
                           1
                           );
  // Spin
  ros::spin ();
}

Я просто внес некоторые изменения, чтобы показать, как это должно быть, но я не тестировал это, поэтому, вероятно, вам нужно будет исправить это еще раз. Надеюсь, этот ответ вам поможет. Кроме того, я не знаю, как алгоритм ICP будет работать при первом обратном вызове, когда облако Final пусто. Кроме того, я рекомендую немного понизить выборку данных, иначе он будет использовать невероятно огромные объемы памяти и процессора после выполнения этого для некоторых кадров.

person api55    schedule 03.03.2015
comment
Да, ICP выравнивает источник по цели. Это дает преобразованное исходное облако. Я пытался добавить преобразованные cloud2_in (source_cloud) и cloud_in (target_cloud) вместе, чтобы получить глобальную карту. Теперь я понимаю, что вместо этого мне придется добавить исходное облако. Я также согласен на уменьшение разрешения. Ваш код дал мне хорошую отправную точку для сохранения кадров Final=tmp_cloud. Однако, как вы упомянули, для первой итерации мне понадобится Final: тогда я думал о первых 2 кадрах ?. Как я могу захватить следующий кадр, если обратный вызов может принимать только 1 облако точек за раз? Если заявление возможно? - person asidd; 03.03.2015
comment
@asidd вы всегда можете проверить количество точек в облаке точек, если оно равно 0, тогда просто добавьте, поскольку это новое облако, если оно не равно 0, выполните обычную процедуру. Помните, что у вас есть только одно облако. Чтобы проверить количество баллов, выполните: int n = Final->points.size();, а затем простой if. Для субдискретизации я использую сетку вокселей из библиотеки pcl. вот руководство - person api55; 03.03.2015
comment
Points.size сделали свое дело! В конце концов, я сделал Final+=tmp_cloud, чтобы сохранить выровненное облако точек плюс целевое облако точек. Мне пришлось немного повозиться с параметрами, чтобы сделать их более надежными и точными. Понижение частоты дискретизации с помощью воксельного фильтра также значительно сократило время вычислений. Спасибо. - person asidd; 04.03.2015