LCOV - code coverage report
Current view: top level - src/PointCloud - LidarInterpreter.cpp (source / functions) Hit Total Coverage
Test: HLR Lines: 65 96 67.7 %
Date: 2018-01-09 08:28:10 Functions: 4 9 44.4 %

          Line data    Source code
       1             : #include "LidarInterpreter.hpp"
       2             : 
       3             : #include <pcl/io/pcd_io.h>
       4             : #include <pcl/point_types.h>
       5             : #include <pcl/visualization/cloud_viewer.h>
       6             : 
       7             : #include <pcl/octree/octree.h>
       8             : #include <pcl/octree/octree_impl.h>
       9             : #include <pcl/octree/octree_search.h>
      10             : 
      11             : #include <pcl/PointIndices.h>
      12             : #include <pcl/io/pcd_io.h>
      13             : #include <pcl/segmentation/extract_clusters.h>
      14             : 
      15             : #include <boost/make_shared.hpp>
      16             : 
      17             : #include <pcl/search/kdtree.h>
      18             : 
      19             : #include <iostream>
      20             : 
      21             : namespace HLR
      22             : {
      23             : namespace PointCloud
      24             : {
      25             : unsigned long LidarInterpreter::highest_pointcloud_id = 0;
      26           0 : std::vector<Object> LidarInterpreter::get_objects(
      27             :     const HLR::Vision::CupDetection& detected_cups,
      28             :     const pcl::PointCloud<pcl::PointXYZ>& point_cloud)
      29             : {
      30           0 :     std::vector<Object> objects;
      31           0 :     for (const auto& cup : detected_cups.cups)
      32             :     {
      33             :         // objects.push_back(convert_cup_to_polyhedron(translate_lidar_to_robot_arm(get_centerpoint_from_contour(find_contour(translate_kinect_to_lidar(detected_cups.frame,
      34             :         // cup), point_cloud)))));
      35           0 :         HLR::Vision::CupDetection tempcup;
      36           0 :         tempcup.cups.push_back(cup);
      37             :     }
      38           0 :     double iets = 1;
      39           0 :     PointCloudWithId a = find_contour(iets, point_cloud);
      40           0 :     return objects;
      41             : }
      42             : 
      43           0 : Object LidarInterpreter::convert_cup_to_polyhedron(
      44             :     const LidarInterpreter::Cup& /*cup_in_robot_arm_space*/)
      45             : {
      46           0 :     HLR::PointCloud::Object objects;
      47           0 :     return objects;
      48             : }
      49           0 : LidarInterpreter::Cup LidarInterpreter::translate_lidar_to_robot_arm(
      50             :     const LidarInterpreter::Cup& /*cup_in_lidar_space*/)
      51             : {
      52           0 :     LidarInterpreter::Cup cup;
      53           0 :     return cup;
      54             : }
      55           0 : LidarInterpreter::Cup LidarInterpreter::get_centerpoint_from_contour(
      56             :     const LidarInterpreter::PointCloudWithId& /*point_cloud_with_id*/)
      57             : {
      58           0 :     LidarInterpreter::Cup cup;
      59           0 :     return cup;
      60             : }
      61             : 
      62           2 : LidarInterpreter::PointCloudWithId LidarInterpreter::find_contour(
      63             :     double angle,
      64             :     const pcl::PointCloud<pcl::PointXYZ>& newest_cloud)
      65             : {
      66             :     // Empty PointCloud which is going to contain the pointcloud of the found
      67             :     // cup to return at the end of this function.
      68           2 :     PointCloudWithId newest_pointcloud;
      69             : 
      70             :     // Check if input contains data to prevent program from crashing.
      71           2 :     if (!newest_cloud.empty())
      72             :     {
      73             :         // This function needs a boost shared_pointer to function.
      74             :         auto cloud_pointer =
      75             :             boost::make_shared<const pcl::PointCloud<pcl::PointXYZ>>(
      76           4 :                 newest_cloud);
      77             :         pcl::PointCloud<pcl::PointXYZ>::Ptr cluster_pointer(
      78           4 :             new pcl::PointCloud<pcl::PointXYZ>);
      79             : 
      80             :         // Variables and setup for search algorithm for Euclidian clustering.
      81             :         pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(
      82           4 :             new pcl::search::KdTree<pcl::PointXYZ>);
      83           2 :         kdtree->setInputCloud(cloud_pointer);
      84             : 
      85             :         // Euclidean clustering object.
      86           4 :         pcl::EuclideanClusterExtraction<pcl::PointXYZ> cluster_object;
      87             : 
      88             :         // Set cluster tolerance to 2cm (small values may cause objects to be
      89             :         // divided in several clusters, whereas big values may join objects in a
      90             :         // same cluster).
      91           2 :         cluster_object.setClusterTolerance(0.05);
      92             : 
      93             :         // Set the minimum and maximum number of points that a cluster can have.
      94           2 :         cluster_object.setMinClusterSize(2);
      95           2 :         cluster_object.setMaxClusterSize(100);
      96             : 
      97             :         // Set the search method for Euclidian clustering.
      98           2 :         cluster_object.setSearchMethod(kdtree);
      99             : 
     100             :         // Set input for Euclidian clustering.
     101           2 :         cluster_object.setInputCloud(cloud_pointer);
     102             : 
     103             :         // Output vector for detected clusters.
     104           4 :         std::vector<pcl::PointIndices> clusters;
     105             : 
     106             :         // Function to extract clusters from input cloud.
     107           2 :         cluster_object.extract(clusters);
     108             : 
     109             :         // Loop through every found cluster.
     110          26 :         for (const auto& c : clusters)
     111             :         {
     112             :             // Temporary vector for sorting angles to determine if cluster is
     113             :             // between input angle later on.
     114          50 :             std::vector<double> min_max_angle;
     115             : 
     116             :             // Loop through every point in the cluster.
     117         212 :             for (const auto& k : c.indices)
     118             :             {
     119             :                 // Push back x and y of every point in the min_max_angle vector
     120             :                 // so it can be sorted.
     121         186 :                 min_max_angle.push_back(atan2(
     122         186 :                     cloud_pointer->points[static_cast<unsigned long>(k)].y,
     123         186 :                     cloud_pointer->points[static_cast<unsigned long>(k)].x));
     124             :             }
     125             :             // Check if min_max_angle contains data.
     126          26 :             if (!min_max_angle.empty())
     127             :             {
     128             :                 // Sort angles from low value to high value so the angles can be
     129             :                 // checked later on
     130          26 :                 std::sort(min_max_angle.begin(), min_max_angle.end());
     131             : 
     132             :                 // Check if angle is bigger than min angle and smaller than max
     133             :                 // angle. If true, the found cluster lies within the search
     134             :                 // angle.
     135          52 :                 if (is_angle_in_angle_range(
     136          52 :                         angle, min_max_angle.front(), min_max_angle.back()))
     137             :                 {
     138             :                     // ++ Pointcloud id counter so each found pointcloud cup
     139             :                     // will be unique.
     140           2 :                     highest_pointcloud_id++;
     141             : 
     142             :                     // Set current cup id of pointcloud to return.
     143           2 :                     newest_pointcloud.second =
     144             :                         static_cast<unsigned int>(highest_pointcloud_id);
     145             : 
     146             :                     // Loop through every point in the cluster again.
     147           8 :                     for (const auto& point : c.indices)
     148             :                     {
     149             :                         // Put Points in pointcloud to return because it´s sure
     150             :                         // now this is the right cluster (cup) we are looking
     151             :                         // for.
     152          12 :                         newest_pointcloud.first.points.push_back(
     153             :                             cloud_pointer
     154           6 :                                 ->points[static_cast<unsigned long>(point)]);
     155             :                     }
     156             : 
     157             :                     // Set the rest of the pointcloud parameters.
     158           2 :                     newest_pointcloud.first.width =
     159           2 :                         static_cast<unsigned int>(cloud_pointer->points.size());
     160           2 :                     newest_pointcloud.first.height = 0;
     161           2 :                     newest_pointcloud.first.is_dense = true;
     162             : 
     163             :                     // Push information back to pointcloud to return.
     164           2 :                     pointcloud_database.push_back(newest_pointcloud);
     165             : 
     166             :                     // Because the right cluster (cup) is found in the given
     167             :                     // angle break out of loop.
     168           2 :                     break;
     169             :                 }
     170             :             }
     171             :         }
     172             :     }
     173             :     // Return pointcloud to return.
     174           2 :     return newest_pointcloud;
     175             : }
     176             : 
     177           0 : double LidarInterpreter::translate_kinect_to_lidar(
     178             :     const std::shared_ptr<cv::Mat>& distance_frame,
     179             :     const cv::Point& location_cup)
     180             : {
     181           0 :     const int x_coord_cup = location_cup.x;
     182           0 :     const int x_resolution_img = (*distance_frame).cols;
     183           0 :     const double viewing_angle_kinect = (70.6 * 3.14159265359) / 180; // degrees
     184           0 :     const double distance_kinect_lidar = 0.082;                       // meters
     185             :     const auto distance_kinect_cup = static_cast<double>(
     186           0 :         (*distance_frame).at<float>(location_cup.x, location_cup.y));
     187             : 
     188             :     const double angle_kinect_cup =
     189           0 :         std::asin(2 * x_coord_cup
     190           0 :                   * (std::sin(viewing_angle_kinect / 2) / x_resolution_img));
     191             : 
     192           0 :     const double angle_lidar_cup =
     193           0 :         std::atan((distance_kinect_lidar
     194           0 :                    - distance_kinect_cup * std::sin(angle_kinect_cup))
     195           0 :                   / (distance_kinect_cup * std::cos(angle_kinect_cup)));
     196             : 
     197           0 :     return angle_lidar_cup;
     198             : }
     199             : 
     200          30 : bool LidarInterpreter::is_angle_in_angle_range(double input,
     201             :                                                double min_angle,
     202             :                                                double max_angle)
     203             : {
     204          30 :     double biggest = 2 * std::acos(-1);
     205          30 :     if (input < 0)
     206             :     {
     207          26 :         input = fmod((2 * std::acos(-1) + fmod(input, 2 * std::acos(-1))),
     208          26 :                      2 * std::acos(-1));
     209             :     }
     210          30 :     if (min_angle < 0)
     211             :     {
     212          16 :         min_angle =
     213          16 :             fmod((2 * std::acos(-1) + fmod(min_angle, 2 * std::acos(-1))),
     214          16 :                  2 * std::acos(-1));
     215             :     }
     216          30 :     if (max_angle < 0)
     217             :     {
     218          12 :         max_angle =
     219          12 :             fmod((2 * std::acos(-1) + fmod(max_angle, 2 * std::acos(-1))),
     220          12 :                  2 * std::acos(-1));
     221             :     }
     222             : 
     223          30 :     if (input >= min_angle && input >= max_angle)
     224             :     {
     225           0 :         biggest = input;
     226             :     }
     227          30 :     else if (min_angle >= input && min_angle >= max_angle)
     228             :     {
     229           5 :         biggest = min_angle;
     230             :     }
     231          25 :     else if (max_angle >= input && max_angle >= min_angle)
     232             :     {
     233          25 :         biggest = max_angle;
     234             :     }
     235             : 
     236          30 :     double translation = 2 * std::acos(-1) - biggest;
     237          30 :     input = fmod((translation + input), 2 * std::acos(-1));
     238          30 :     min_angle = fmod((translation + min_angle), 2 * std::acos(-1));
     239          30 :     max_angle = fmod((translation + max_angle), 2 * std::acos(-1));
     240             : 
     241          30 :     if (min_angle > max_angle)
     242             :     {
     243          25 :         std::swap(min_angle, max_angle);
     244             :     }
     245          30 :     if (max_angle > std::acos(-1))
     246             :     {
     247          28 :         return input >= max_angle;
     248             :     }
     249           2 :     return input <= max_angle;
     250             : }
     251             : 
     252             : } // namespace PointCloud
     253           3 : } // namespace HLR

Generated by: LCOV version 1.12