예제 #1
0
 /**
  * Extract a 96 byte descriptor.
  */
 public void extract(GaussianScaleSpacePyramid pyramid,
                     DogFeaturePointStack points, FreakFeaturePointStack store)
 {
     ExtractFREAK84(store, pyramid, points, mPointRing0, mPointRing1,
                    mPointRing2, mPointRing3, mPointRing4, mPointRing5,
                    mSigmaCenter, mSigmaRing0, mSigmaRing1, mSigmaRing2,
                    mSigmaRing3, mSigmaRing4, mSigmaRing5, mExpansionFactor);
 }
        /**
         * Detect scale-invariant feature points given a pyramid.
         * @param _i_dog_feature_points
         * 検出したDOG特徴点
         */
        public void detect(GaussianScaleSpacePyramid i_pyramid, DogFeaturePointStack i_dog_feature_points)
        {
            //clean up 1st feature stack
            DogFeaturePointStack tmp_fp = this._tmp_fps;

            tmp_fp.clear();

            // Compute Laplacian images (DoG)
            this.mLaplacianPyramid.compute(i_pyramid);

            // Detect minima and maximum in Laplacian images
            this.extractFeatures(i_pyramid, this.mLaplacianPyramid, tmp_fp);

            // Sub-pixel refinement
            this.findSubpixelLocations(i_pyramid, tmp_fp);

            // Compute the gradient pyramid
            this.mOrientationAssignment.computeGradients(i_pyramid);

            AreaBuckit abuckit = this.mBuckets;


            if (tmp_fp.getLength() <= abuckit._buckit.Length)
            {
                //特徴点の数が要求数以下なら全てのポイントを使う。
                for (int i = 0; i < tmp_fp.getLength(); i++)
                {
                    this.addFeatureOrientations(i_pyramid, tmp_fp.getItem(i), i_dog_feature_points);
                }
            }
            else
            {
                //特徴点を選別(Prune features)

                // Clear the previous state
                abuckit.clear();

                // Insert each features into a bucket
                for (int i = 0; i < tmp_fp.getLength(); i++)
                {
                    DogFeaturePoint p = tmp_fp.getItem(i);
                    abuckit.put(p.x, p.y, i, Math.Abs(p.score));
                }
                // Compute an orientation for each feature point
                for (int i = 0; i < abuckit._buckit.Length; i++)
                {
                    if (abuckit._buckit[i].first == 0)
                    {
                        continue;
                    }
                    this.addFeatureOrientations(i_pyramid, tmp_fp.getItem(abuckit._buckit[i].second), i_dog_feature_points);
                }
            }

            return;
        }
        public static NyARNftFreakFsetFile genFeatureSet3(NyARNftIsetFile i_iset_file)
        {
            int max_features = 500;
            DogFeaturePointStack   _dog_feature_points = new DogFeaturePointStack(max_features);
            FreakFeaturePointStack query_keypoint      = new FreakFeaturePointStack(max_features);
            //
            List <NyARNftFreakFsetFile.RefDataSet> refdataset = new List <NyARNftFreakFsetFile.RefDataSet>();
            List <NyARNftFreakFsetFile.ImageInfo>  imageinfo  = new List <NyARNftFreakFsetFile.ImageInfo>();

            for (int ii = 0; ii < i_iset_file.items.Length; ii++)
            {
                NyARNftIsetFile.ReferenceImage rimg         = i_iset_file.items[ii];
                FREAKExtractor            mFeatureExtractor = new FREAKExtractor();
                int                       octerves          = BinomialPyramid32f.octavesFromMinimumCoarsestSize(rimg.width, rimg.height, 8);
                BinomialPyramid32f        _pyramid          = new BinomialPyramid32f(rimg.width, rimg.height, octerves, 3);
                DoGScaleInvariantDetector _dog_detector     = new DoGScaleInvariantDetector(rimg.width, rimg.height, octerves, 3, 3, 4, max_features);

                //RefDatasetの作成
                _pyramid.build(NyARGrayscaleRaster.createInstance(rimg.width, rimg.height, NyARBufferType.INT1D_GRAY_8, rimg.img));
                // Detect feature points
                _dog_feature_points.clear();
                _dog_detector.detect(_pyramid, _dog_feature_points);

                // Extract features
                query_keypoint.clear();
                mFeatureExtractor.extract(_pyramid, _dog_feature_points, query_keypoint);

                for (int i = 0; i < query_keypoint.getLength(); i++)
                {
                    FreakFeaturePoint ffp = query_keypoint.getItem(i);
                    NyARNftFreakFsetFile.RefDataSet rds = new NyARNftFreakFsetFile.RefDataSet();
                    rds.pageNo     = 1;
                    rds.refImageNo = ii;
                    rds.coord2D.setValue(ffp.x, ffp.y);
                    rds.coord3D.setValue((ffp.x + 0.5f) / rimg.dpi * 25.4f, ((rimg.height - 0.5f) - ffp.y) / rimg.dpi * 25.4f);
                    rds.featureVec.angle  = ffp.angle;
                    rds.featureVec.maxima = ffp.maxima ? 1 : 0;
                    rds.featureVec.scale  = ffp.scale;
                    ffp.descripter.getValueLe(rds.featureVec.v);
                    refdataset.Add(rds);
                }
                imageinfo.Add(new NyARNftFreakFsetFile.ImageInfo(rimg.width, rimg.height, ii));
            }
            NyARNftFreakFsetFile.PageInfo[] pi = new NyARNftFreakFsetFile.PageInfo[1];
            pi[0] = new NyARNftFreakFsetFile.PageInfo(1, imageinfo.ToArray());
            return(new NyARNftFreakFsetFile(refdataset.ToArray(), pi));
        }
        /**
         * Sub-pixel refinement.
         */
        private void findSubpixelLocations(GaussianScaleSpacePyramid pyramid, DogFeaturePointStack i_dog_fp)
        {
            int    num_points;
            double laplacianSqrThreshold;
            double hessianThreshold;

            num_points            = 0;
            laplacianSqrThreshold = (this.mLaplacianThreshold * this.mLaplacianThreshold);
            double te = (mEdgeThreshold + 1);

            hessianThreshold = ((te * te) / mEdgeThreshold);

            for (int i = 0; i < i_dog_fp.getLength(); i++)
            {
                DogFeaturePoint kp = i_dog_fp.getItem(i);
                //assert kp.scale < mLaplacianPyramid.numScalePerOctave();
                // ASSERT(kp.scale < mLaplacianPyramid.numScalePerOctave(),
                // "Feature point scale is out of bounds");
                int lap_index = kp.octave * mLaplacianPyramid.numScalePerOctave() + kp.scale;

                // Get Laplacian images
                LaplacianImage lap0 = mLaplacianPyramid.get(lap_index - 1);
                LaplacianImage lap1 = mLaplacianPyramid.get(lap_index);
                LaplacianImage lap2 = mLaplacianPyramid.get(lap_index + 1);

                // Compute the Hessian
                if (!this.updateLocation(kp, lap0, lap1, lap2))
                {
                    continue;
                }


                if (Math.Abs(kp.edge_score) < hessianThreshold && (kp.score * kp.score) >= laplacianSqrThreshold &&
                    kp.x >= 0 && kp.x < mLaplacianPyramid.get(0).getWidth() && kp.y >= 0 &&
                    kp.y < mLaplacianPyramid.get(0).getHeight())
                {
                    // Update the sigma
                    kp.sigma = pyramid.effectiveSigma(kp.octave, kp.sp_scale);
                    i_dog_fp.swap(i, num_points++);
                }
            }
            i_dog_fp.setLength(num_points);
        }
예제 #5
0
        /**
         * Extract the descriptors for all the feature points.
         */
        private void ExtractFREAK84(FreakFeaturePointStack store,
                                    GaussianScaleSpacePyramid pyramid, DogFeaturePointStack points,
                                    double[] points_ring0, double[] points_ring1, double[] points_ring2,
                                    double[] points_ring3, double[] points_ring4, double[] points_ring5,
                                    double sigma_center, double sigma_ring0, double sigma_ring1,
                                    double sigma_ring2, double sigma_ring3, double sigma_ring4,
                                    double sigma_ring5, double expansion_factor)
        {
            // ASSERT(pyramid, "Pyramid is NULL");
            // ASSERT(store.size() == points.size(),
            // "Feature store has not been allocated");
            for (int i = 0; i < points.getLength(); i++)
            {
                FreakFeaturePoint sp = store.prePush();
                if (sp == null)
                {
                    prepush_wawning();
                    break;
                }
                DogFeaturePoint pt = points.getItem(i);
                if (!ExtractFREAK84(sp.descripter,
                                    pyramid, pt, points_ring0, points_ring1,
                                    points_ring2, points_ring3, points_ring4, points_ring5,
                                    sigma_center, sigma_ring0, sigma_ring1, sigma_ring2,
                                    sigma_ring3, sigma_ring4, sigma_ring5, expansion_factor

                                    ))
                {
                    store.pop();
                    continue;
                }
                sp.angle  = pt.angle;
                sp.x      = pt.x;
                sp.y      = pt.y;
                sp.scale  = pt.sigma;
                sp.maxima = pt.score > 0;
                //			store.point(num_points).set(points[i]);
            }
        }
        private void addFeatureOrientations(GaussianScaleSpacePyramid i_pyramid, DogFeaturePoint dfp, DogFeaturePointStack i_ot_fps)
        {
            double[] tmp = this._addFeatureOrientations_tmp;


            double x, y, s;

            // Down sample the point to the detected octave
            bilinear_downsample_point(tmp, dfp.x, dfp.y, dfp.sigma, dfp.octave);
            x = tmp[0];
            y = tmp[1];
            s = tmp[2];

            // Downsampling the point can cause (x,y) to leave the image bounds
            // by
            // a tiny amount. Here we just clip it to be within the image
            // bounds.
            x = ClipScalar(x, 0, i_pyramid.get(dfp.octave, 0).getWidth() - 1);
            y = ClipScalar(y, 0, i_pyramid.get(dfp.octave, 0).getHeight() - 1);

            // Compute dominant orientations
            int num_angles = mOrientationAssignment.compute(dfp.octave, dfp.scale, x, y, s, this.mOrientations);

            // Create a feature point for each angle
            for (int j = 0; j < num_angles; j++)
            {
                // Copy the feature point
                DogFeaturePoint fp = i_ot_fps.prePush();
                if (fp == null)
                {
                    //中断
                    //				prepush_warning();
                    break;
                }
                fp.x          = dfp.x;
                fp.y          = dfp.y;
                fp.octave     = dfp.octave;
                fp.scale      = dfp.scale;
                fp.sp_scale   = dfp.sp_scale;
                fp.score      = dfp.score;
                fp.sigma      = dfp.sigma;
                fp.edge_score = dfp.edge_score;
                fp.angle      = mOrientations[j];
            }
            return;
        }
        /**
         * Extract the minima/maxima.
         */
        private void extractFeatures(GaussianScaleSpacePyramid pyramid, DoGPyramid laplacian, DogFeaturePointStack i_dog_fp)
        {
            double laplacianSqrThreshold = (this.mLaplacianThreshold * this.mLaplacianThreshold);

            for (int i = 1; i < mLaplacianPyramid.size() - 1; i++)
            {
                LaplacianImage im0  = laplacian.get(i - 1);
                LaplacianImage im1  = laplacian.get(i);
                LaplacianImage im2  = laplacian.get(i + 1);
                double[]       im0b = (double[])im0.getBuffer();
                double[]       im1b = (double[])im1.getBuffer();
                double[]       im2b = (double[])im2.getBuffer();

                int octave = laplacian.octaveFromIndex((int)i);
                int scale  = laplacian.scaleFromIndex((int)i);

                if (im0.getWidth() == im1.getWidth() && im0.getWidth() == im2.getWidth())
                { // All images are the
                  // same size
                  // ASSERT(im0.height() == im1.height(), "Height is inconsistent");
                  // ASSERT(im0.height() == im2.height(), "Height is inconsistent");

                    int width_minus_1 = im1.getWidth() - 1;
                    int heigh_minus_1 = im1.getHeight() - 1;

                    for (int row = 1; row < heigh_minus_1; row++)
                    {
                        int im0_ym1 = im0.get(row - 1);
                        int im0_y   = im0.get(row);
                        int im0_yp1 = im0.get(row + 1);

                        int im1_ym1 = im1.get(row - 1);
                        int im1_y   = im1.get(row);
                        int im1_yp1 = im1.get(row + 1);

                        int im2_ym1 = im2.get(row - 1);
                        int im2_y   = im2.get(row);
                        int im2_yp1 = im2.get(row + 1);

                        for (int col = 1; col < width_minus_1; col++)
                        {
                            double value = im1b[im1_y + col];

                            // Check laplacian score
                            if ((value * value) < laplacianSqrThreshold)
                            {
                                continue;
                            }
                            bool extrema = false;
                            if (value > im0b[im0_ym1 + col - 1] && value > im0b[im0_ym1 + col] &&
                                value > im0b[im0_ym1 + col + 1] && value > im0b[im0_y + col - 1] &&
                                value > im0b[im0_y + col] && value > im0b[im0_y + col + 1] &&
                                value > im0b[im0_yp1 + col - 1] && value > im0b[im0_yp1 + col] &&
                                value > im0b[im0_yp1 + col + 1] &&
                                /* im1 - 8 evaluations */
                                value > im1b[im1_ym1 + col - 1] && value > im1b[im1_ym1 + col] &&
                                value > im1b[im1_ym1 + col + 1] && value > im1b[im1_y + col - 1] &&
                                value > im1b[im1_y + col + 1] && value > im1b[im1_yp1 + col - 1] &&
                                value > im1b[im1_yp1 + col] && value > im1b[im1_yp1 + col + 1] &&
                                /* im2 - 9 evaluations */
                                value > im2b[im2_ym1 + col - 1] && value > im2b[im2_ym1 + col] &&
                                value > im2b[im2_ym1 + col + 1] && value > im2b[im2_y + col - 1] &&
                                value > im2b[im2_y + col] && value > im2b[im2_y + col + 1] &&
                                value > im2b[im2_yp1 + col - 1] && value > im2b[im2_yp1 + col] &&
                                value > im2b[im2_yp1 + col + 1])
                            {
                                extrema = true;
                            }
                            else if (value < im0b[im0_ym1 + col - 1] && value < im0b[im0_ym1 + col] &&
                                     value < im0b[im0_ym1 + col + 1] && value < im0b[im0_y + col - 1] &&
                                     value < im0b[im0_y + col] && value < im0b[im0_y + col + 1] &&
                                     value < im0b[im0_yp1 + col - 1] && value < im0b[im0_yp1 + col] &&
                                     value < im0b[im0_yp1 + col + 1] &&
                                     /* im1 - 8 evaluations */
                                     value < im1b[im1_ym1 + col - 1] && value < im1b[im1_ym1 + col] &&
                                     value < im1b[im1_ym1 + col + 1] && value < im1b[im1_y + col - 1] &&
                                     value < im1b[im1_y + col + 1] && value < im1b[im1_yp1 + col - 1] &&
                                     value < im1b[im1_yp1 + col] && value < im1b[im1_yp1 + col + 1] &&
                                     /* im2 - 9 evaluations */
                                     value < im2b[im2_ym1 + col - 1] && value < im2b[im2_ym1 + col] &&
                                     value < im2b[im2_ym1 + col + 1] && value < im2b[im2_y + col - 1] &&
                                     value < im2b[im2_y + col] && value < im2b[im2_y + col + 1] &&
                                     value < im2b[im2_yp1 + col - 1] && value < im2b[im2_yp1 + col] &&
                                     value < im2b[im2_yp1 + col + 1])
                            {
                                extrema = true;
                            }

                            if (extrema)
                            {
                                DogFeaturePoint fp = i_dog_fp.prePush();
                                if (fp == null)
                                {
                                    prepush_warning();
                                    break;
                                }
                                fp.octave = octave;
                                fp.scale  = scale;
                                fp.score  = value;
                                fp.sigma  = pyramid.effectiveSigma(octave, scale);
                                double[] tmp = new double[2];
                                bilinear_upsample_point(tmp, col, row, octave);
                                fp.x = tmp[0];
                                fp.y = tmp[1];
                            }
                        }
                    }
                }
                else if (im0.getWidth() == im1.getWidth() && (im1.getWidth() >> 1) == im2.getWidth())
                {
                    int end_x = (int)Math.Floor(((im2.getWidth() - 1) - 0.5f) * 2.0f + 0.5f);
                    int end_y = (int)Math.Floor(((im2.getHeight() - 1) - 0.5f) * 2.0f + 0.5f);

                    for (int row = 2; row < end_y; row++)
                    {
                        int im0_ym1 = im0.get(row - 1);
                        int im0_y   = im0.get(row);
                        int im0_yp1 = im0.get(row + 1);

                        int im1_ym1 = im1.get(row - 1);
                        int im1_y   = im1.get(row);
                        int im1_yp1 = im1.get(row + 1);

                        for (int col = 2; col < end_x; col++)
                        {
                            double value = im1b[im1_y + col];

                            // Check laplacian score
                            if ((value * value) < laplacianSqrThreshold)
                            {
                                continue;
                            }

                            // Compute downsampled point location
                            double ds_x = col * 0.5f - 0.25f;
                            double ds_y = row * 0.5f - 0.25f;

                            bool extrema = false;
                            if (
                                /* im0 - 9 evaluations */
                                value > im0b[im0_ym1 + col - 1] && value > im0b[im0_ym1 + col] &&
                                value > im0b[im0_ym1 + col + 1] && value > im0b[im0_y + col - 1] &&
                                value > im0b[im0_y + col] && value > im0b[im0_y + col + 1] &&
                                value > im0b[im0_yp1 + col - 1] && value > im0b[im0_yp1 + col] &&
                                value > im0b[im0_yp1 + col + 1] &&
                                /* im1 - 8 evaluations */
                                value > im1b[im1_ym1 + col - 1] && value > im1b[im1_ym1 + col] &&
                                value > im1b[im1_ym1 + col + 1] && value > im1b[im1_y + col - 1] &&
                                value > im1b[im1_y + col + 1] && value > im1b[im1_yp1 + col - 1] &&
                                value > im1b[im1_yp1 + col] && value > im1b[im1_yp1 + col + 1] &&
                                /* im2 - 9 evaluations */
                                value > im2.bilinearInterpolation(ds_x - 0.5f, ds_y - 0.5f) &&
                                value > im2.bilinearInterpolation(ds_x, ds_y - 0.5f) &&
                                value > im2.bilinearInterpolation(ds_x + 0.5f, ds_y - 0.5f) &&
                                value > im2.bilinearInterpolation(ds_x - 0.5f, ds_y) &&
                                value > im2.bilinearInterpolation(ds_x, ds_y) &&
                                value > im2.bilinearInterpolation(ds_x + 0.5f, ds_y) &&
                                value > im2.bilinearInterpolation(ds_x - 0.5f, ds_y + 0.5f) &&
                                value > im2.bilinearInterpolation(ds_x, ds_y + 0.5f) &&
                                value > im2.bilinearInterpolation(ds_x + 0.5f, ds_y + 0.5f))
                            {
                                extrema = true;
                            }
                            else if (
                                /* im0 - 9 evaluations */
                                value < im0b[im0_ym1 + col - 1] && value < im0b[im0_ym1 + col] &&
                                value < im0b[im0_ym1 + col + 1] && value < im0b[im0_y + col - 1] &&
                                value < im0b[im0_y + col] && value < im0b[im0_y + col + 1] &&
                                value < im0b[im0_yp1 + col - 1] && value < im0b[im0_yp1 + col] &&
                                value < im0b[im0_yp1 + col + 1] &&
                                /* im1 - 8 evaluations */
                                value < im1b[im1_ym1 + col - 1] && value < im1b[im1_ym1 + col] &&
                                value < im1b[im1_ym1 + col + 1] && value < im1b[im1_y + col - 1] &&
                                value < im1b[im1_y + col + 1] && value < im1b[im1_yp1 + col - 1] &&
                                value < im1b[im1_yp1 + col] && value < im1b[im1_yp1 + col + 1] &&
                                /* im2 - 9 evaluations */
                                value < im2.bilinearInterpolation(ds_x - 0.5f, ds_y - 0.5f) &&
                                value < im2.bilinearInterpolation(ds_x, ds_y - 0.5f) &&
                                value < im2.bilinearInterpolation(ds_x + 0.5f, ds_y - 0.5f) &&
                                value < im2.bilinearInterpolation(ds_x - 0.5f, ds_y) &&
                                value < im2.bilinearInterpolation(ds_x, ds_y) &&
                                value < im2.bilinearInterpolation(ds_x + 0.5f, ds_y) &&
                                value < im2.bilinearInterpolation(ds_x - 0.5f, ds_y + 0.5f) &&
                                value < im2.bilinearInterpolation(ds_x, ds_y + 0.5f) &&
                                value < im2.bilinearInterpolation(ds_x + 0.5f, ds_y + 0.5f))
                            {
                                extrema = true;
                            }

                            if (extrema)
                            {
                                DogFeaturePoint fp = i_dog_fp.prePush();
                                if (fp == null)
                                {
                                    prepush_warning();
                                    break;
                                }
                                fp.octave = octave;
                                fp.scale  = scale;
                                fp.score  = value;
                                fp.sigma  = pyramid.effectiveSigma(octave, scale);
                                double[] tmp = new double[2];
                                bilinear_upsample_point(tmp, col, row, octave);
                                fp.x = tmp[0];
                                fp.y = tmp[1];
                            }
                        }
                    }
                }
                else if ((im0.getWidth() >> 1) == im1.getWidth() && (im0.getWidth() >> 1) == im2.getWidth())
                {
                    int width_minus_1  = im1.getWidth() - 1;
                    int height_minus_1 = im1.getHeight() - 1;

                    for (int row = 1; row < height_minus_1; row++)
                    {
                        int im1_ym1 = im1.get(row - 1);
                        int im1_y   = im1.get(row);
                        int im1_yp1 = im1.get(row + 1);

                        int im2_ym1 = im2.get(row - 1);
                        int im2_y   = im2.get(row);
                        int im2_yp1 = im2.get(row + 1);

                        for (int col = 1; col < width_minus_1; col++)
                        {
                            double value = im1b[im1_y + col];

                            // Check laplacian score
                            if ((value * value) < laplacianSqrThreshold)
                            {
                                continue;
                            }

                            double us_x = (col << 1) + 0.5f;
                            double us_y = (row << 1) + 0.5f;

                            bool extrema = false;
                            if (value > im1b[im1_ym1 + col - 1] && value > im1b[im1_ym1 + col] &&
                                value > im1b[im1_ym1 + col + 1] && value > im1b[im1_y + col - 1] &&
                                value > im1b[im1_y + col + 1] && value > im1b[im1_yp1 + col - 1] &&
                                value > im1b[im1_yp1 + col] && value > im1b[im1_yp1 + col + 1] &&
                                /* im2 - 9 evaluations */
                                value > im2b[im2_ym1 + col - 1] && value > im2b[im2_ym1 + col] &&
                                value > im2b[im2_ym1 + col + 1] && value > im2b[im2_y + col - 1] &&
                                value > im2b[im2_y + col] && value > im2b[im2_y + col + 1] &&
                                value > im2b[im2_yp1 + col - 1] && value > im2b[im2_yp1 + col] &&
                                value > im2b[im2_yp1 + col + 1] &&
                                /* im2 - 9 evaluations */
                                value > im0.bilinearInterpolation(us_x - 2.0f, us_y - 2.0f) &&
                                value > im0.bilinearInterpolation(us_x, us_y - 2.0f) &&
                                value > im0.bilinearInterpolation(us_x + 2.0f, us_y - 2.0f) &&
                                value > im0.bilinearInterpolation(us_x - 2.0f, us_y) &&
                                value > im0.bilinearInterpolation(us_x, us_y) &&
                                value > im0.bilinearInterpolation(us_x + 2.0f, us_y) &&
                                value > im0.bilinearInterpolation(us_x - 2.0f, us_y + 2.0f) &&
                                value > im0.bilinearInterpolation(us_x, us_y + 2.0f) &&
                                value > im0.bilinearInterpolation(us_x + 2.0f, us_y + 2.0f))
                            {
                                extrema = true;
                            }
                            else if (value < im1b[im1_ym1 + col - 1] && value < im1b[im1_ym1 + col] &&
                                     value < im1b[im1_ym1 + col + 1] && value < im1b[im1_y + col - 1] &&
                                     value < im1b[im1_y + col + 1] && value < im1b[im1_yp1 + col - 1] &&
                                     value < im1b[im1_yp1 + col] && value < im1b[im1_yp1 + col + 1] &&
                                     /* im2 - 9 evaluations */
                                     value < im2b[im2_ym1 + col - 1] && value < im2b[im2_ym1 + col] &&
                                     value < im2b[im2_ym1 + col + 1] && value < im2b[im2_y + col - 1] &&
                                     value < im2b[im2_y + col] && value < im2b[im2_y + col + 1] &&
                                     value < im2b[im2_yp1 + col - 1] && value < im2b[im2_yp1 + col] &&
                                     value < im2b[im2_yp1 + col + 1] &&
                                     /* im2 - 9 evaluations */
                                     value < im0.bilinearInterpolation(us_x - 2.0f, us_y - 2.0f) &&
                                     value < im0.bilinearInterpolation(us_x, us_y - 2.0f) &&
                                     value < im0.bilinearInterpolation(us_x + 2.0f, us_y - 2.0f) &&
                                     value < im0.bilinearInterpolation(us_x - 2.0f, us_y) &&
                                     value < im0.bilinearInterpolation(us_x, us_y) &&
                                     value < im0.bilinearInterpolation(us_x + 2.0f, us_y) &&
                                     value < im0.bilinearInterpolation(us_x - 2.0f, us_y + 2.0f) &&
                                     value < im0.bilinearInterpolation(us_x, us_y + 2.0f) &&
                                     value < im0.bilinearInterpolation(us_x + 2.0f, us_y + 2.0f))
                            {
                                extrema = true;
                            }

                            if (extrema)
                            {
                                DogFeaturePoint fp = i_dog_fp.prePush();
                                if (fp == null)
                                {
                                    prepush_warning();
                                    break;
                                }
                                fp.octave = octave;
                                fp.scale  = scale;
                                fp.score  = value;
                                fp.sigma  = pyramid.effectiveSigma(octave, scale);
                                double[] tmp = new double[2];
                                bilinear_upsample_point(tmp, col, row, octave);
                                fp.x = tmp[0];
                                fp.y = tmp[1];
                            }
                        }
                    }
                }
            }
            return;
        }