Problem with FLANN in a multithreaded application

asked 2013-10-14 05:41:17 -0500

Artem gravatar image

updated 2013-10-14 08:59:02 -0500

Hello!

I have a problem with running opencv code in multiple threads. When I do not use flann, the program runs ok even in multiple treads. But when I am adding flann based functions I get the exception "OpenCV Error: Assertion failed (0 <= _rowRange.start && _rowRange.start <= _rowRange.end && _rowRange.end <= m.rows) in Mat, file /tmp/opencv-KNTZ/opencv-2.4.4/modules/core/src/matrix.cpp, line 284" at some moment (different each time) during multithreaded execution.

Is flann implemetation known to be not thread-safe, or there might be a problem with something else?

Thank you in advance, Artem

P. S. In the folowing I provide the code, where the problem occurs. But there is actually no matrix operations involved, at least explicitly.

float getError(float max_dist,  const std::vector<cv::Point2f>& initial_points, const cv::detail::ImageFeatures& features_from,  const cv::detail::ImageFeatures& features_to, const cv::Mat& homography, Grid* grid) {


    std::vector<cv::Point2f> transformed_points;
    cv::perspectiveTransform(initial_points, transformed_points, homography);


    const float kRadius = 4.0;

    const float kMaxDescriptorDistance = max_dist;
    const float kGamma = kRadius + 2.0;

    cv::BFMatcher matcher(cv::NORM_HAMMING2);

    int matches_count = 0;
    double error = 0.0;


    cv::Rect referenceRect = cv::Rect(cv::Point(0,0), features_to.img_size);


    std::vector<int> indicies;
    std::vector<float> distanses;

    for (int point_ind = 0; point_ind < (int)transformed_points.size(); ++point_ind) {
        if (!referenceRect.contains(transformed_points[point_ind])) {
            continue;
        }


        grid->radiusSearch(transformed_points[point_ind], &indicies, &distanses);

        if (!indicies.empty()) {
            int min_ind = -1;
            float min_dist = std::numeric_limits<float>::max();
            for (int rind = 0; rind < (int)indicies.size(); ++rind) {
                std::vector<cv::DMatch> matches;
                matcher.match(features_from.descriptors.row(point_ind), features_to.descriptors.row(indicies[rind]), matches);

                if (matches[0].distance < kMaxDescriptorDistance) {
                    if (matches[0].distance < min_dist) {
                        min_dist = matches[0].distance;
                        min_ind = rind;
                    }

                }
            }

            if (min_ind >= 0) {

                std::vector<cv::DMatch> matches;
                matcher.match(features_from.descriptors.row(point_ind), features_to.descriptors.row(indicies[min_ind]), matches);

                error += distanses[min_ind];
                ++matches_count;
            }
        }
    }

    error += kGamma * (initial_points.size() - matches_count);

    return error;

}

And here is the code for class grid, which make use of flann

 class Grid {
                public:
                    Grid(unsigned int rows, unsigned int cols, unsigned int row_bins = 7, unsigned int col_bins = 5);
                    std::pair<unsigned int, unsigned int> getGridPoint(cv::Point2f pt);
                    void addKeyPoint(const cv::KeyPoint& kp);
                    void buildIndecies();
                    void radiusSearch(const cv::Point2f& pt, std::vector<int>* result, std::vector<float>* distanses, float radius = 2, unsigned int num_results = 4);
                private:
                    unsigned int rows_;
                    unsigned int cols_;
                    unsigned int row_bins_;
                    unsigned int col_bins_;
                    std::vector<float> upper_row_limits_;
                    std::vector<float> upper_col_limits_;
                    std::vector<std::vector<std::vector<cv::Point> > > grid_of_points_;
                    std::vector<std::vector<cv::flann::Index> > grid_of_flann_;
  };


void Grid::radiusSearch(const cv::Point2f& pt, std::vector<int>* result, std::vector<float>* distanses, float radius, unsigned int num_results) {
            std::vector<float> query(2);
            std::vector<int> indicies(num_results, -1);
            std::vector<float> dists(num_results, -1.0);

            std::pair<unsigned int, unsigned int> inds = this->getGridPoint(pt);

            query[0] = pt.x;
            query[1] = pt.y;

            result->clear();
            distanses->clear();
            int cur_result_num = 0;

            if (grid_of_points_[inds.first][inds.second].size() > 4) {

                 cur_result_num =  grid_of_flann_[inds.first][inds.second].radiusSearch(query, indicies, dists ...
(more)
edit retag flag offensive close merge delete

Comments

1

We cant help if you dont show us some code. The error indicates that you try to create a Mat from another Mat with a region of interest that is bigger than the actual Mat.

Moster gravatar imageMoster ( 2013-10-14 07:04:54 -0500 )edit
1

How does the constructor of your grid class look like? Also, could you be a bit more exact in which function or maybe even which line it crashes?

Moster gravatar imageMoster ( 2013-10-14 09:42:00 -0500 )edit

Well, Moster, thank you. Your comments helped me a lot.

The exception arise at this line

matcher.match(features_from.descriptors.row(point_ind), features_to.descriptors.row(indicies[rind]), matches); (the only actually where some submatrices are used).

And the reason for that is that in a call for flann radius search

cur_result_num = grid_of_flann_[inds.first][inds.second].radiusSearch(query, indicies, dists, radius, num_results);

the number of results returned (cur_result_num) could be greater than the maximum number of results specified (num_results). I misunderstood this point.

It is not yet clear for me why this exeption doesn't show up in a single thread, but nevertheless the problem is solved for now.

Thank you again

Artem gravatar imageArtem ( 2013-10-14 10:21:37 -0500 )edit