StatusWith<NearStage::CoveredInterval*> // GeoNear2DStage::nextInterval(OperationContext* txn, WorkingSet* workingSet, Collection* collection) { // The search is finished if we searched at least once and all the way to the edge if (_currBounds.getInner() >= 0 && _currBounds.getOuter() == _fullBounds.getOuter()) { return StatusWith<CoveredInterval*>(NULL); } // // Setup the next interval // const NearStats* stats = getNearStats(); if (!stats->intervalStats.empty()) { const IntervalStats& lastIntervalStats = stats->intervalStats.back(); // TODO: Generally we want small numbers of results fast, then larger numbers later if (lastIntervalStats.numResultsBuffered < 300) _boundsIncrement *= 2; else if (lastIntervalStats.numResultsBuffered > 600) _boundsIncrement /= 2; } _boundsIncrement = max(_boundsIncrement, min2DBoundsIncrement(_nearParams.nearQuery, _twoDIndex)); R2Annulus nextBounds(_currBounds.center(), _currBounds.getOuter(), min(_currBounds.getOuter() + _boundsIncrement, _fullBounds.getOuter())); const bool isLastInterval = (nextBounds.getOuter() == _fullBounds.getOuter()); _currBounds = nextBounds; // // Get a covering region for this interval // const CRS queryCRS = _nearParams.nearQuery.centroid.crs; auto_ptr<R2Region> coverRegion; if (FLAT == queryCRS) { // NOTE: Due to floating point math issues, FLAT searches of a 2D index need to treat // containment and distance separately. // Ex: (distance) 54.001 - 54 > 0.001, but (containment) 54 + 0.001 <= 54.001 // The idea is that a $near search with bounds is really a $within search, sorted by // distance. We attach a custom $within : annulus matcher to do the $within search, // and adjust max/min bounds slightly since, as above, containment does not mean the // distance calculation won't slightly overflow the boundary. // // The code below adjusts: // 1) Overall min/max bounds of the generated distance intervals to be more inclusive // 2) Bounds of the interval covering to be more inclusive // ... and later on we add the custom $within : annulus matcher. // // IMPORTANT: The *internal* interval distance bounds are *exact thresholds* - these // should not be adjusted. // TODO: Maybe integrate annuluses as a standard shape, and literally transform $near // internally into a $within query with $near just as sort. // Compute the maximum axis-aligned distance error const double epsilon = std::numeric_limits<double>::epsilon() * (max(abs(_fullBounds.center().x), abs(_fullBounds.center().y)) + _fullBounds.getOuter()); if (nextBounds.getInner() > 0 && nextBounds.getInner() == _fullBounds.getInner()) { nextBounds = R2Annulus(nextBounds.center(), max(0.0, nextBounds.getInner() - epsilon), nextBounds.getOuter()); } if (nextBounds.getOuter() > 0 && nextBounds.getOuter() == _fullBounds.getOuter()) { // We're at the max bound of the search, adjust interval maximum nextBounds = R2Annulus(nextBounds.center(), nextBounds.getInner(), nextBounds.getOuter() + epsilon); } // *Always* adjust the covering bounds to be more inclusive coverRegion.reset(new R2Annulus(nextBounds.center(), max(0.0, nextBounds.getInner() - epsilon), nextBounds.getOuter() + epsilon)); } else { invariant(SPHERE == queryCRS); // TODO: As above, make this consistent with $within : $centerSphere // Our intervals aren't in the same CRS as our index, so we need to adjust them coverRegion.reset(new R2Annulus(projectBoundsToTwoDDegrees(nextBounds))); } // // Setup the stages for this interval // IndexScanParams scanParams; scanParams.descriptor = _twoDIndex; scanParams.direction = 1; // We use a filter on the key. The filter rejects keys that don't intersect with the // annulus. An object that is in the annulus might have a key that's not in it and a key // that's in it. As such we can't just look at one key per object. // // This does force us to do our own deduping of results, though. scanParams.doNotDedup = true; // Scan bounds on 2D indexes are only over the 2D field - other bounds aren't applicable. // This is handled in query planning. scanParams.bounds = _nearParams.baseBounds; // The "2d" field is always the first in the index const string twoDFieldName = _nearParams.nearQuery.field; const int twoDFieldPosition = 0; OrderedIntervalList coveredIntervals; coveredIntervals.name = scanParams.bounds.fields[twoDFieldPosition].name; ExpressionMapping::cover2d(*coverRegion, _twoDIndex->infoObj(), internalGeoNearQuery2DMaxCoveringCells, &coveredIntervals); // Intersect the $near bounds we just generated into the bounds we have for anything else // in the scan (i.e. $within) IndexBoundsBuilder::intersectize(coveredIntervals, &scanParams.bounds.fields[twoDFieldPosition]); // These parameters are stored by the index, and so must be ok GeoHashConverter::Parameters hashParams; GeoHashConverter::parseParameters(_twoDIndex->infoObj(), &hashParams); MatchExpression* keyMatcher = new TwoDKeyInRegionExpression(coverRegion.release(), hashParams, twoDFieldName); // 2D indexes support covered search over additional fields they contain // TODO: Don't need to clone, can just attach to custom matcher above if (_nearParams.filter) { AndMatchExpression* andMatcher = new AndMatchExpression(); andMatcher->add(keyMatcher); andMatcher->add(_nearParams.filter->shallowClone()); keyMatcher = andMatcher; } // IndexScanWithMatch owns the matcher IndexScan* scan = new IndexScanWithMatch(txn, scanParams, workingSet, keyMatcher); MatchExpression* docMatcher = NULL; // FLAT searches need to add an additional annulus $within matcher, see above if (FLAT == queryCRS) { docMatcher = new TwoDPtInAnnulusExpression(_fullBounds, twoDFieldName); } // FetchStage owns index scan FetchStage* fetcher(new FetchStageWithMatch(workingSet, scan, docMatcher, collection)); return StatusWith<CoveredInterval*>(new CoveredInterval(fetcher, true, nextBounds.getInner(), nextBounds.getOuter(), isLastInterval)); }
StatusWith<NearStage::CoveredInterval*> // GeoNear2DSphereStage::nextInterval(OperationContext* txn, WorkingSet* workingSet, Collection* collection) { // The search is finished if we searched at least once and all the way to the edge if (_currBounds.getInner() >= 0 && _currBounds.getOuter() == _fullBounds.getOuter()) { return StatusWith<CoveredInterval*>(NULL); } // // Setup the next interval // const NearStats* stats = getNearStats(); if (!stats->intervalStats.empty()) { const IntervalStats& lastIntervalStats = stats->intervalStats.back(); // TODO: Generally we want small numbers of results fast, then larger numbers later if (lastIntervalStats.numResultsBuffered < 300) _boundsIncrement *= 2; else if (lastIntervalStats.numResultsBuffered > 600) _boundsIncrement /= 2; } R2Annulus nextBounds(_currBounds.center(), _currBounds.getOuter(), min(_currBounds.getOuter() + _boundsIncrement, _fullBounds.getOuter())); bool isLastInterval = (nextBounds.getOuter() == _fullBounds.getOuter()); _currBounds = nextBounds; // // Setup the covering region and stages for this interval // IndexScanParams scanParams; scanParams.descriptor = _s2Index; scanParams.direction = 1; // We use a filter on the key. The filter rejects keys that don't intersect with the // annulus. An object that is in the annulus might have a key that's not in it and a key // that's in it. As such we can't just look at one key per object. // // This does force us to do our own deduping of results, though. scanParams.doNotDedup = true; scanParams.bounds = _nearParams.baseBounds; // Because the planner doesn't yet set up 2D index bounds, do it ourselves here const string s2Field = _nearParams.nearQuery.field; const int s2FieldPosition = getFieldPosition(_s2Index, s2Field); scanParams.bounds.fields[s2FieldPosition].intervals.clear(); OrderedIntervalList* coveredIntervals = &scanParams.bounds.fields[s2FieldPosition]; TwoDSphereKeyInRegionExpression* keyMatcher = new TwoDSphereKeyInRegionExpression(_currBounds, s2Field); ExpressionMapping::cover2dsphere(keyMatcher->getRegion(), _s2Index->infoObj(), coveredIntervals); // IndexScan owns the hash matcher IndexScan* scan = new IndexScanWithMatch(txn, scanParams, workingSet, keyMatcher); // FetchStage owns index scan FetchStage* fetcher(new FetchStage(workingSet, scan, _nearParams.filter, collection)); return StatusWith<CoveredInterval*>(new CoveredInterval(fetcher, true, nextBounds.getInner(), nextBounds.getOuter(), isLastInterval)); }
void alignToPrevImage(Mat imgPrevUnAlligned,Mat imgNextUnAlligned, Mat &imgPrev,Mat &imgNext){ int rows=imgPrevUnAlligned.rows; int cols=imgPrevUnAlligned.cols; int chans=imgPrevUnAlligned.channels(); cout << "cols " << cols << " rows " << rows << " chans " << chans << endl; unsigned char * imgPrevPtr = (unsigned char *)imgPrevUnAlligned.data; unsigned char * imgNextPtr = (unsigned char *)imgNextUnAlligned.data; int iOff = 0; int jOff = 0; int blockSize = 70; int Wind = 100; float s = 1.3; int jStop = (rows/s + Wind); int iStop = (cols/s + Wind); int jStart = (rows/s - Wind); int iStart = (cols/s - Wind); int jRef = (jStart + jStop)/2; int iRef = (iStart + iStop)/2; //Create the window from which the template is to be matched. Mat windImg; Rect window(iRef-Wind/2,jRef-Wind/2,Wind,Wind); imgNextUnAlligned(window).copyTo(windImg); windImg = imgNextUnAlligned; //namedWindow("window Image",CV_WINDOW_NORMAL); //imshow("window Image",windImg); //cvWaitKey(0); //Create the template Mat templateImage; Rect temp(iRef-blockSize/2,jRef-blockSize/2,blockSize,blockSize); imgPrevUnAlligned(temp).copyTo(templateImage); //namedWindow("window Image",CV_WINDOW_NORMAL); //imshow("window Image",templateImage); //cvWaitKey(0); int r_cols = windImg.cols-templateImage.cols+1; int r_rows = windImg.rows-templateImage.rows+1; Mat result(r_cols,r_rows,CV_32FC1); matchTemplate(windImg,templateImage,result,CV_TM_CCORR_NORMED); double minVal; double maxVal; Point minLoc; Point maxLoc; Point matchLoc; minMaxLoc(result,&minVal,&maxVal,&minLoc,&maxLoc,Mat()); matchLoc = maxLoc; //rectangle(windImg,matchLoc,Point(matchLoc.x+templateImage.cols,matchLoc.y+templateImage.rows),Scalar::all(0),2,4,0); //rectangle(result,matchLoc,Point(matchLoc.x+templateImage.cols,matchLoc.y+templateImage.rows),Scalar::all(0),2,4,0); iOff =-( matchLoc.x -iRef+blockSize/2); jOff = -(matchLoc.y - jRef+blockSize/2); cout << iOff << "," << jOff << endl; int newH = imgPrevUnAlligned.rows - abs(jOff); int newW = imgPrevUnAlligned.cols - abs(iOff); Rect prevBounds(iOff > 0? iOff : 0, jOff < 0? 0 : jOff,newW,newH); imgPrevUnAlligned(prevBounds).copyTo(imgPrev); Rect nextBounds(iOff > 0? 0 : -iOff, jOff < 0? -jOff : 0,newW,newH); imgNextUnAlligned(nextBounds).copyTo(imgNext); /* namedWindow("result prev",CV_WINDOW_NORMAL); imshow("result prev",imgPrev); cvWaitKey(0); namedWindow("result next",CV_WINDOW_NORMAL); imshow("result next",imgNext); cvWaitKey(0); return; */ }