void R2RegionCoverer::getCovering( const R2Region& region, vector<GeoHash>* cover ) { // Strategy: Start with the full plane. Discard any // that do not intersect the shape. Then repeatedly choose the // largest cell that intersects the shape and subdivide it. // // _result contains the cells that will be part of the output, while the // queue contains cells that we may still subdivide further. Cells that // are entirely contained within the region are immediately added to the // output, while cells that do not intersect the region are immediately // discarded. Therefore the queue only contains cells that partially // intersect the region. Candidates are prioritized first according to // cell size (larger cells first), then by the number of intersecting // children they have (fewest children first), and then by the number of // fully contained children (fewest children first). verify(_minLevel <= _maxLevel); dassert(_candidateQueue->empty()); dassert(_results->empty()); _region = ®ion; getInitialCandidates(); while(!_candidateQueue->empty()) { Candidate* candidate = _candidateQueue->top().second; // Owned _candidateQueue->pop(); LOG(3) << "Pop: " << candidate->cell; // Try to expand this cell into its children if (candidate->cell.getBits() < _minLevel || candidate->numChildren == 1 || (int)_results->size() + (int)_candidateQueue->size() + candidate->numChildren <= _maxCells) { for (int i = 0; i < candidate->numChildren; i++) { addCandidate(candidate->children[i]); } deleteCandidate(candidate, false); } else { // Reached max cells. Move all candidates from the queue into results. candidate->isTerminal = true; addCandidate(candidate); } LOG(3) << "Queue: " << _candidateQueue->size(); } _region = NULL; cover->swap(*_results); }
std::vector<PipelineGrid> GridFitter::fitGrid(const Tag& tag, const TagCandidate &candidate) { #ifdef DEBUG_GRIDFITTER cv::destroyAllWindows(); #endif const Ellipse& ellipse_orig = candidate.getEllipse(); // region of interest of tag candidate const cv::Size2i roiSize = tag.getRoi().size(); cv::Mat roi; tag.getRepresentations().clahe.copyTo(roi); cv::Mat binarizedROI(roiSize, CV_8UC1); cv::adaptiveThreshold(roi, binarizedROI, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, _settings.get_adaptive_block_size(), _settings.get_adaptive_c()); cv::Mat blurredRoi; cv::GaussianBlur(roi, blurredRoi, cv::Size(3, 3), 0, 0, cv::BORDER_DEFAULT); auto getSobel = [&](const int dx, const int dy) { cv::Mat sobelImg; cv::Scharr(blurredRoi, sobelImg, CV_32F, dx, dy); static const double ksize = 3.; const double denom = std::pow(2., ksize * 2. - dx - dy - 2); sobelImg.convertTo(sobelImg, CV_8UC1, 1. / (2. * denom), 255. / 2.); return sobelImg; }; cv::Mat edgeRoiX = getSobel(1, 0); cv::Mat edgeRoiY = getSobel(0, 1); // TODO: constant/setting for axis border // TODO: add sanity checks const cv::Mat ellipseMask = candidate.getEllipse().getMask(cv::Size(10, 10)); cv::Mat equalizedRoi; roi.copyTo(equalizedRoi, ellipseMask); cv::equalizeHist(equalizedRoi, roi); // get initial candidates using brute force search over small number of // rotations and position offsets candidate_set gridCandidates = getInitialCandidates(binarizedROI, edgeRoiX, edgeRoiY, ellipse_orig, roi); #ifdef DEBUG_GRIDFITTER visualizeDebug(gridCandidates, roi, roiSize, edgeRoiX, edgeRoiY, tag, binarizedROI, "candidate", _settings.get_gradient_num_initial()); #endif // optimize best candidates using gradient descent GradientDescent optimizer(gridCandidates, roi, binarizedROI, edgeRoiX, edgeRoiY, _settings_cache); optimizer.optimize(); const candidate_set& bestGrids = optimizer.getBestGrids(); #ifdef DEBUG_GRIDFITTER std::cout << "min initial candidate error: " << gridCandidates.begin()->error << std::endl; std::cout << "min final candidate error: " << bestGrids.begin()->error << std::endl; visualizeDebug(bestGrids, roi, roiSize, edgeRoiX, edgeRoiY, tag, binarizedROI, "best fit", _settings.get_gradient_num_results()); #endif // return the settings.numResults best candidates std::vector<PipelineGrid> results; { const size_t to = std::min(_settings.get_gradient_num_results(), bestGrids.size()); size_t idx = 0; for (candidate_t const& gridCandidate : bestGrids) { Util::gridconfig_t const& config = gridCandidate.config; results.emplace_back(config.center + tag.getRoi().tl(), config.radius, config.angle_z, config.angle_y, config.angle_x, gridCandidate.error); ++idx; if (idx == to) break; } } return results; }