2016-04-25 9 views
0

Ich habe eine Funktion erstellt, die die normalen Vektoren einer 3D-Punktwolke schätzt und es braucht viel Zeit, um auf einer Wolke der Größe 2 Millionen zu laufen. Ich möchte multi-thread, indem Sie die gleiche Funktion auf zwei verschiedenen Punkten gleichzeitig aufrufen, aber es hat nicht funktioniert (es erstellt Hunderte von Threads). Hier ist, was ich versucht:Wie wird Multithreading innerhalb einer Schleife verwendet, die in C++ durch eine Punktwolke iteriert?

// 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; 
    } 
} 

Wie Sie sehen Ich versuche, die gleiche Funktion auf 3 verschiedenen Punkten in der gleichen Zeit zu nennen. Irgendwelche Vorschläge, wie das funktioniert? Sorry für den schlechten Code, ich bin müde und danke im Voraus.

EDIT: Hier ist die find_normal Funktion Hier sind die Parameter:

@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(); 
    } 
+0

Ich denke, dass die Verwendung von Threads, wie Sie es mit Boost getan haben, für diese Aufgabe übertrieben ist. Werfen Sie einen Blick auf OpenMP und ähnliche Bibliotheken (Cilk, TBB). – iksemyonov

+0

Außerdem sieht es so aus, als müssten Sie das gewünschte Ergebnis besser definieren. Im Moment ist es nicht ganz klar, ob Sie alle Punkte unabhängig und parallel verarbeiten wollen oder ob es ein bestimmtes Muster gibt, wenn Sie die Funktion auf Punkte anwenden ("die gleiche Funktion an zwei Punkten aufrufen"). – iksemyonov

+0

ist es, es funktioniert definitiv nicht. Ich habe von TBB gehört, bin mir aber nicht sicher, ob es mit meiner Punktwolke funktioniert. Ich werde es versuchen, danke. –

Antwort

0

Da ich recht verstehe es nicht, wie die Ergebnisdaten gespeichert wird, werde ich eine Lösung vorzuschlagen, basierend auf OpenMP, das mit dem von Ihnen geposteten Code übereinstimmt.

// 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); 
} 

Beachten Sie, dass die < Vergleich verwenden sollten, und nicht die != ein, -Das ist wie OpenMP funktioniert (es will Random Access-Iteratoren). Ich verwende den Zeitplan static, da jedes Element mehr oder weniger identische Zeit für die Verarbeitung benötigt. Wenn das nicht der Fall ist, versuchen Sie stattdessen schedule(dynamic).

Diese Lösung verwendet OpenMP und Sie können z. TBB ebenfalls, obwohl es eine höhere Eingangsbarriere als OpenMP hat und eine OOP-ähnliche API verwendet.

Auch wiederholen, was ich bereits in den Kommentaren gesagt habe: OpenMP sowie TBB werden Thread-Management und Lastverteilung für Sie behandeln. Sie geben nur Hinweise (wie schedule(static)), wie Sie es tun, um Ihren Bedürfnissen besser gerecht zu werden.

Andere als das, bitte, gewöhnen Sie sich an, so wenig Code wie möglich zu wiederholen; Idealerweise sollte kein Code dupliziert werden. Z.B. Wenn Sie viele Variablen desselben Typs deklarieren oder eine bestimmte Funktion einige Male nacheinander mit einem ähnlichen Muster aufrufen, sehe ich auch eine übermäßige Kommentierung im Code mit einem unklaren Grund dahinter.

+0

Das sieht wirklich gut aus, es ist definitiv ein Ort, um anzufangen. Wie für die Ergebnisdaten wird es nur in einer Textdatei am Ende gespeichert. Die Punkte in der Cloud werden direkt transformiert, dh es wird keine neue Cloud erstellt, die gespeichert werden kann. Der Prozess ist wie folgt: > Ich lese eine Wolke aus einer Textdatei; > Ich mache einige Operationen darauf; > Ich schreibe die transformierte Wolke (die die gleiche Referenz aber eine modifizierte Wolke ist) in eine Datei. –

+0

@VladAdrianMoglan, ich bekomme die allgemeine Idee jetzt scheint es; Wenn das Ergebnis in genau die gleiche Position * zurückkehrt, dann funktioniert mein Code. Achte auf die Fälle, in denen du das Element "i" nimmst und das Ergebnis in eine andere Position "j" bringst! – iksemyonov

+0

Genau, das ist der Fall. Wie auch immer, спасибо für die Hilfe –

Verwandte Themen