Problem with FLANN in a multithreaded application
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 ...
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.
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?
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