RANSAC shape detection, no primitive detected after multiple runs.

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

RANSAC shape detection, no primitive detected after multiple runs.

LingjieZhu
Hello,

When I tried to use the "Point Set Shape Detection" package and ran the example code multiple times, the program seemed normal at first but would output zero primitive eventually.
It seems that the "clear" operation called by the "set_input" function doesn't clear everything. Is there anything that I am missing?

Thanks,
Andrew Liu

Here is the code:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/property_map.h>
#include <CGAL/Timer.h>
#include <CGAL/number_utils.h>
#include <CGAL/Shape_detection_3.h>
#include <iostream>
#include <fstream>
// Type declarations
typedef CGAL::Exact_predicates_inexact_constructions_kernel  Kernel;
typedef Kernel::FT                                           FT;
typedef std::pair<Kernel::Point_3, Kernel::Vector_3>         Point_with_normal;
typedef std::vector<Point_with_normal>                       Pwn_vector;
typedef CGAL::First_of_pair_property_map<Point_with_normal>  Point_map;
typedef CGAL::Second_of_pair_property_map<Point_with_normal> Normal_map;
// In Efficient_RANSAC_traits the basic types, i.e., Point and Vector types
// as well as iterator type and property maps, are defined.
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits<Kernel,
    Pwn_vector, Point_map, Normal_map>            Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits>   Efficient_ransac;
typedef CGAL::Shape_detection_3::Plane<Traits>              Plane;
int main()
{
    // Points with normals.
    Pwn_vector points;
    // Loads point set from a file.
    // read_xyz_points_and_normals takes an OutputIterator for storing the points
    // and a property map to store the normal vector with each point.
    std::ifstream stream("data/cube.pwn");
    if (!stream ||
        !CGAL::read_xyz_points_and_normals(stream,
            std::back_inserter(points),
            Point_map(),
            Normal_map()))
    {
        std::cerr << "Error: cannot read file cube.pwn" << std::endl;
        return EXIT_FAILURE;
    }
    // Instantiates shape detection engine.
    Efficient_ransac ransac;

    const Pwn_vector pts_origin = points;
    for (std::size_t i = 0; i < 30; ++i) {
        points = pts_origin;
        // Provides the input data.
        ransac.set_input(points);
        // Registers detection of planes
        ransac.add_shape_factory<Plane>();
        // Measures time before setting up the shape detection.
        CGAL::Timer time;
        time.start();
        // Build internal data structures.
        ransac.preprocess();
        // Measures time after preprocessing.
        time.stop();
        std::cout << "preprocessing took: " << time.time() * 1000 << "ms" << std::endl;
        // Perform detection several times and choose result with highest coverage.
        Efficient_ransac::Shape_range shapes = ransac.shapes();
        FT best_coverage = 0;
        for (size_t i = 0; i < 6; i++) {
            // Reset timer.
            time.reset();
            time.start();
            // Detects shapes.
            ransac.detect();
            // Measures time after detection.
            time.stop();
            // Compute coverage, i.e. ratio of the points assigned to a shape.
            FT coverage = FT(points.size() - ransac.number_of_unassigned_points())
                / FT(points.size());
            // Prints number of assigned shapes and unsassigned points.
            std::cout << "time: " << time.time() * 1000 << "ms" << std::endl;
            std::cout << ransac.shapes().end() - ransac.shapes().begin() << " primitives, "
                << coverage << " coverage" << std::endl;

            // Choose result with highest coverage.
            if (coverage > best_coverage) {
                best_coverage = coverage;
                // Efficient_ransac::shapes() provides
                // an iterator range to the detected shapes.
                shapes = ransac.shapes();
            }
        }
    }

    return EXIT_SUCCESS;
}
Reply | Threaded
Open this post in threaded view
|

Re: RANSAC shape detection, no primitive detected after multiple runs.

Simon Giraudot-2
Hello Andrew,

Thank you for your report, I investigated and it turns out that it is indeed a bug: the method clear() should call clear_shape_factories() but does not, which means that at every iterations, there's a new shape factory (for Planes) added (which explains why the algorithms gets slower and slower although I'm not sure why this makes it detect 0 shapes after a while).

I'll fix this in the CGAL code. In the mean time, if you want your code to work with the current version, you can simply move the line
ransac.add_shape_factory<Plane>();
before the loop (right after "Efficient_ransac ransac;" for example).

Best,

-- 
Simon Giraudot, PhD
R&D Engineer
GeometryFactory - http://geometryfactory.com/

Le 19/02/2017 à 14:25, AndrewLiu a écrit :
Hello,

When I tried to use the "Point Set Shape Detection" package and ran the
example code multiple times, the program seemed normal at first but would
output zero primitive eventually.
It seems that the "clear" operation called by the "set_input" function
doesn't clear everything. Is there anything that I am missing?

Thanks,
Andrew Liu

Here is the code:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/property_map.h>
#include <CGAL/Timer.h>
#include <CGAL/number_utils.h>
#include <CGAL/Shape_detection_3.h>
#include <iostream>
#include <fstream>
// Type declarations
typedef CGAL::Exact_predicates_inexact_constructions_kernel  Kernel;
typedef Kernel::FT                                           FT;
typedef std::pair<Kernel::Point_3, Kernel::Vector_3>        
Point_with_normal;
typedef std::vector<Point_with_normal>                       Pwn_vector;
typedef CGAL::First_of_pair_property_map<Point_with_normal>  Point_map;
typedef CGAL::Second_of_pair_property_map<Point_with_normal> Normal_map;
// In Efficient_RANSAC_traits the basic types, i.e., Point and Vector types
// as well as iterator type and property maps, are defined.
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits<Kernel,
    Pwn_vector, Point_map, Normal_map>            Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits>  
Efficient_ransac;
typedef CGAL::Shape_detection_3::Plane<Traits>              Plane;
int main()
{
    // Points with normals.
    Pwn_vector points;
    // Loads point set from a file. 
    // read_xyz_points_and_normals takes an OutputIterator for storing the
points
    // and a property map to store the normal vector with each point.
    std::ifstream stream("data/cube.pwn");
    if (!stream ||
        !CGAL::read_xyz_points_and_normals(stream,
            std::back_inserter(points),
            Point_map(),
            Normal_map()))
    {
        std::cerr << "Error: cannot read file cube.pwn" << std::endl;
        return EXIT_FAILURE;
    }
    // Instantiates shape detection engine.
    Efficient_ransac ransac;

    const Pwn_vector pts_origin = points;
    for (std::size_t i = 0; i < 30; ++i) {
        points = pts_origin;
        // Provides the input data.
        ransac.set_input(points);
        // Registers detection of planes
        ransac.add_shape_factory<Plane>();
        // Measures time before setting up the shape detection.
        CGAL::Timer time;
        time.start();
        // Build internal data structures.
        ransac.preprocess();
        // Measures time after preprocessing.
        time.stop();
        std::cout << "preprocessing took: " << time.time() * 1000 << "ms" <<
std::endl;
        // Perform detection several times and choose result with highest
coverage.
        Efficient_ransac::Shape_range shapes = ransac.shapes();
        FT best_coverage = 0;
        for (size_t i = 0; i < 6; i++) {
            // Reset timer.
            time.reset();
            time.start();
            // Detects shapes.
            ransac.detect();
            // Measures time after detection.
            time.stop();
            // Compute coverage, i.e. ratio of the points assigned to a
shape.
            FT coverage = FT(points.size() -
ransac.number_of_unassigned_points())
                / FT(points.size());
            // Prints number of assigned shapes and unsassigned points.
            std::cout << "time: " << time.time() * 1000 << "ms" <<
std::endl;
            std::cout << ransac.shapes().end() - ransac.shapes().begin() <<
" primitives, "
                << coverage << " coverage" << std::endl;

            // Choose result with highest coverage.
            if (coverage > best_coverage) {
                best_coverage = coverage;
                // Efficient_ransac::shapes() provides
                // an iterator range to the detected shapes. 
                shapes = ransac.shapes();
            }
        }
    }

    return EXIT_SUCCESS;
}



--
View this message in context: http://cgal-discuss.949826.n4.nabble.com/RANSAC-shape-detection-no-primitive-detected-after-multiple-runs-tp4662529.html
Sent from the cgal-discuss mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|

Re: RANSAC shape detection, no primitive detected after multiple runs.

LingjieZhu
Hi Simon,

Thanks for your investigation, your solution works as expected.

Here is another issue in the same package. Since CGAL::Shape_detection_3::Efficient_RANSAC<Traits>::Shape_range doesn't have a default constructor, we have to write something like
    m_shapes(boost::make_shared<std::vector<boost::shared_ptr<Efficient_ransac::Shape>>>())
in the constructor initializer list to initialize a class data member m_shapes of the Shape_range type. This is tedious and needs extra knowledge of the type and data structure of the package. Maybe a default constructor will reduce that burden.

Best,

-----原始邮件-----
发件人: "Simon Giraudot" <[hidden email]>
发送时间: 2017年3月6日 星期一
收件人: [hidden email]
抄送:
主题: Re: [cgal-discuss] RANSAC shape detection, no primitive detected after multiple runs.

Hello Andrew,

Thank you for your report, I investigated and it turns out that it is indeed a bug: the method clear() should call clear_shape_factories() but does not, which means that at every iterations, there's a new shape factory (for Planes) added (which explains why the algorithms gets slower and slower although I'm not sure why this makes it detect 0 shapes after a while).

I'll fix this in the CGAL code. In the mean time, if you want your code to work with the current version, you can simply move the line
ransac.add_shape_factory<Plane>();
before the loop (right after "Efficient_ransac ransac;" for example).

Best,

-- 
Simon Giraudot, PhD
R&D Engineer
GeometryFactory - http://geometryfactory.com/

Le 19/02/2017 à 14:25, AndrewLiu a écrit :
Hello,

When I tried to use the "Point Set Shape Detection" package and ran the
example code multiple times, the program seemed normal at first but would
output zero primitive eventually.
It seems that the "clear" operation called by the "set_input" function
doesn't clear everything. Is there anything that I am missing?

Thanks,
Andrew Liu

Here is the code:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/property_map.h>
#include <CGAL/Timer.h>
#include <CGAL/number_utils.h>
#include <CGAL/Shape_detection_3.h>
#include <iostream>
#include <fstream>
// Type declarations
typedef CGAL::Exact_predicates_inexact_constructions_kernel  Kernel;
typedef Kernel::FT                                           FT;
typedef std::pair<Kernel::Point_3, Kernel::Vector_3>        
Point_with_normal;
typedef std::vector<Point_with_normal>                       Pwn_vector;
typedef CGAL::First_of_pair_property_map<Point_with_normal>  Point_map;
typedef CGAL::Second_of_pair_property_map<Point_with_normal> Normal_map;
// In Efficient_RANSAC_traits the basic types, i.e., Point and Vector types
// as well as iterator type and property maps, are defined.
typedef CGAL::Shape_detection_3::Efficient_RANSAC_traits<Kernel,
    Pwn_vector, Point_map, Normal_map>            Traits;
typedef CGAL::Shape_detection_3::Efficient_RANSAC<Traits>  
Efficient_ransac;
typedef CGAL::Shape_detection_3::Plane<Traits>              Plane;
int main()
{
    // Points with normals.
    Pwn_vector points;
    // Loads point set from a file. 
    // read_xyz_points_and_normals takes an OutputIterator for storing the
points
    // and a property map to store the normal vector with each point.
    std::ifstream stream("data/cube.pwn");
    if (!stream ||
        !CGAL::read_xyz_points_and_normals(stream,
            std::back_inserter(points),
            Point_map(),
            Normal_map()))
    {
        std::cerr << "Error: cannot read file cube.pwn" << std::endl;
        return EXIT_FAILURE;
    }
    // Instantiates shape detection engine.
    Efficient_ransac ransac;

    const Pwn_vector pts_origin = points;
    for (std::size_t i = 0; i < 30; ++i) {
        points = pts_origin;
        // Provides the input data.
        ransac.set_input(points);
        // Registers detection of planes
        ransac.add_shape_factory<Plane>();
        // Measures time before setting up the shape detection.
        CGAL::Timer time;
        time.start();
        // Build internal data structures.
        ransac.preprocess();
        // Measures time after preprocessing.
        time.stop();
        std::cout << "preprocessing took: " << time.time() * 1000 << "ms" <<
std::endl;
        // Perform detection several times and choose result with highest
coverage.
        Efficient_ransac::Shape_range shapes = ransac.shapes();
        FT best_coverage = 0;
        for (size_t i = 0; i < 6; i++) {
            // Reset timer.
            time.reset();
            time.start();
            // Detects shapes.
            ransac.detect();
            // Measures time after detection.
            time.stop();
            // Compute coverage, i.e. ratio of the points assigned to a
shape.
            FT coverage = FT(points.size() -
ransac.number_of_unassigned_points())
                / FT(points.size());
            // Prints number of assigned shapes and unsassigned points.
            std::cout << "time: " << time.time() * 1000 << "ms" <<
std::endl;
            std::cout << ransac.shapes().end() - ransac.shapes().begin() <<
" primitives, "
                << coverage << " coverage" << std::endl;

            // Choose result with highest coverage.
            if (coverage > best_coverage) {
                best_coverage = coverage;
                // Efficient_ransac::shapes() provides
                // an iterator range to the detected shapes. 
                shapes = ransac.shapes();
            }
        }
    }

    return EXIT_SUCCESS;
}



--
View this message in context: http://cgal-discuss.949826.n4.nabble.com/RANSAC-shape-detection-no-primitive-detected-after-multiple-runs-tp4662529.html
Sent from the cgal-discuss mailing list archive at Nabble.com.