如何在循环中使用多线程来迭代C ++中的点云?

时间:2016-04-25 18:46:11

标签: c++ multithreading for-loop thread-safety boost-thread

我已经制作了一个估算3D点云的法向量的函数,并且需要花费大量时间才能在200万像素的云上运行。我想通过同时在两个不同的点上调用相同的函数来进行多线程但它不起作用(它创建了数百个线程)。这是我试过的:

// kd-tree used for finding neighbours
pcl::KdTreeFLANN<pcl::PointXYZRGB> kdt;

// cloud iterators
pcl::PointCloud<pcl::PointXYZRGB>::iterator cloud_it = pt_cl->points.begin();
pcl::PointCloud<pcl::PointXYZRGB>::iterator cloud_it1;
pcl::PointCloud<pcl::PointXYZRGB>::iterator cloud_it2;
pcl::PointCloud<pcl::PointXYZRGB>::iterator cloud_it3;
pcl::PointCloud<pcl::PointXYZRGB>::iterator cloud_it4;

// initializing tree
kdt.setInputCloud(pt_cl);

// loop exit condition
bool it_completed = false;

while (!it_completed)
{
    // initializing cloud iterators
    cloud_it1 = cloud_it;
    cloud_it2 = cloud_it++;
    cloud_it3 = cloud_it++;

    if (cloud_it3 != pt_cl->points.end())
    {
        // attaching threads
        boost::thread thread_1 = boost::thread(geom::vectors::find_normal, pt_cl, cloud_it1, kdt, radius, max_neighbs);
        boost::thread thread_2 = boost::thread(geom::vectors::find_normal, pt_cl, cloud_it2, kdt, radius, max_neighbs);
        boost::thread thread_3 = boost::thread(geom::vectors::find_normal, pt_cl, cloud_it3, kdt, radius, max_neighbs);

        // joining threads
        thread_1.join();
        thread_2.join();
        thread_3.join();

        cloud_it++;
    }

    else
    {
        it_completed = true;
    }
}

正如您所看到的,我试图同时在3个不同的点上调用相同的功能。有关如何使这项工作的任何建议?对不起代码很糟糕,我很累,并且提前谢谢你。

编辑:这是find_normal函数 以下是参数:

@param pt_cl is a pointer to the point cloud to be treated (pcl::PointCloud<PointXYZRGB>::Ptr)
@param cloud_it is an iterator of this cloud (pcl::PointCloud<PointXYZRGB>::iterator)
@param kdt is the kd_tree used to find the closest neighbours of a point
@param radius defines the range in which to search for the neighbours of a point
@param max_neighbs is the maximum number of neighbours to be returned by the radius search

// auxilliary vectors for the k-tree nearest search
    std::vector<int> pointIdxRadiusSearch; // neighbours ids
    std::vector<float> pointRadiusSquaredDistance; // distances from the source to the neighbours

    // the vectors of which the cross product calculates the normal
    geom::vectors::vector3 *vect1;
    geom::vectors::vector3 *vect2;
    geom::vectors::vector3 *cross_prod;
    geom::vectors::vector3 *abs_cross_prod;
    geom::vectors::vector3 *normal;
    geom::vectors::vector3 *normalized_normal;

    // vectors to average
    std::vector<geom::vectors::vector3> vct_toavg;

    // if there are neighbours left
    if (kdt.radiusSearch(*cloud_it, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance, max_neighbs) > 0)
    {

        for (int pt_index = 0; pt_index < (pointIdxRadiusSearch.size() - 1); pt_index++)
        {
            // defining the first vector
            vect1 = geom::vectors::create_vect2p((*cloud_it), pt_cl->points[pointIdxRadiusSearch[pt_index + 1]]);

            // defining the second vector; making sure there is no 'out of bounds' error
            if (pt_index == pointIdxRadiusSearch.size() - 2)
                vect2 = geom::vectors::create_vect2p((*cloud_it), pt_cl->points[pointIdxRadiusSearch[1]]);


            else
                vect2 = geom::vectors::create_vect2p((*cloud_it), pt_cl->points[pointIdxRadiusSearch[pt_index + 2]]);

            // adding the cross product of the two previous vectors to our list
            cross_prod = geom::vectors::cross_product(*vect1, *vect2);
            abs_cross_prod = geom::aux::abs_vector(*cross_prod);
            vct_toavg.push_back(*abs_cross_prod);

            // freeing memory
            delete vect1;
            delete vect2;
            delete cross_prod;
            delete abs_cross_prod;
        }

        // calculating the normal
        normal = geom::vectors::vect_avg(vct_toavg);

        // calculating the normalized normal
        normalized_normal = geom::vectors::normalize_normal(*normal);

        // coloring the point
        geom::aux::norm_toPtRGB(&(*cloud_it), *normalized_normal);

        // freeing memory
        delete normal;
        delete normalized_normal;

        // clearing vectors
        vct_toavg.clear();
        pointIdxRadiusSearch.clear();
        pointRadiusSquaredDistance.clear();

        // shrinking vectors
        vct_toavg.shrink_to_fit();
        pointIdxRadiusSearch.shrink_to_fit();
        pointRadiusSquaredDistance.shrink_to_fit();
    }

1 个答案:

答案 0 :(得分:0)

由于我不太了解结果数据的存储方式,因此我建议使用与您发布的代码相匹配的OpenMP解决方案。

// kd-tree used for finding neighbours
pcl::KdTreeFLANN<pcl::PointXYZRGB> kdt;

#pragma openmp parallel for schedule(static)
for (pcl::PointCloud<pcl::PointXYZRGB>::iterator cloud_it = pt_cl->points.begin();
    cloud_it < pt_cl.end();
    ++cloud_it) {
    geom::vectors::find_normal, pt_cl, cloud_it, kdt, radius, max_neighbs);
}

请注意,您应该使用<比较,而不是!=,比较OpenMP的工作方式(它需要随机访问迭代器)。我使用static计划,因为每个元素应该花费或多或少相同的时间来处理。如果情况并非如此,请尝试使用schedule(dynamic)

此解决方案使用OpenMP,您可以调查,例如TBB也有,但它比OpenMP具有更高的入口门槛,并使用OOP风格的API。

另外,重复我在评论中已经说过的内容:OpenMP和TBB将为您处理线程管理和负载分配。您只需传递有关如何操作的提示(例如schedule(static)),以便更好地满足您的需求。

除此之外,请尽量重复尽可能少的代码;理想情况下,不应复制任何代码。例如。当你声明许多相同类型的变量,或者连续几次使用类似模式调用某个函数时,我也会在代码中看到过多的注释,背后有一个不明原因。