예제 #1
0
    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));
    }
예제 #2
0
    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));
    }
예제 #3
0
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;
		*/

}