コード例 #1
0
        /**
         * Extract a descriptor from the pyramid for a single point.
         */
        bool ExtractFREAK84(
            LongDescripter768 i_desc,    // unsigned char desc[84],
            GaussianScaleSpacePyramid pyramid, DogFeaturePoint point,
            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)
        {
            double[] samples = new double[37];

            // Create samples
            if (!SamplePyramidFREAK84(samples, pyramid, point, 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))
            {
                return(false);
            }

            // Once samples are created compute descriptor
            CompareFREAK84(i_desc, samples);

            return(true);
        }
        /**
         * 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;
        }
        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;
        }
        /**
         * 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]);
            }
        }
コード例 #6
0
        /**
         * Sample all the receptors from the pyramid given a single point.
         */
        bool SamplePyramidFREAK84(double[] samples,
                                  GaussianScaleSpacePyramid pyramid, DogFeaturePoint point,
                                  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)
        {
            double[] S = new double[9];

            double[] c  = new double[2];
            double[] r0 = new double[2 * 6];
            double[] r1 = new double[2 * 6];
            double[] r2 = new double[2 * 6];
            double[] r3 = new double[2 * 6];
            double[] r4 = new double[2 * 6];
            double[] r5 = new double[2 * 6];

            double sc, s0, s1, s2, s3, s4, s5;

            // Ensure the scale of the similarity transform is at least "1".
            //		double transform_scale = point.scale * expansion_factor;
            double transform_scale = point.sigma * expansion_factor;

            if (transform_scale < 1)
            {
                transform_scale = 1;
            }

            // Transformation from canonical test locations to image
            Similarity(S, point.x, point.y, point.angle, transform_scale);

            // Locate center points
            c[0] = S[2];
            c[1] = S[5];

            // Locate ring 0 points
            MultiplyPointSimilarityInhomogenous(r0, 0, S, points_ring0, 0);
            MultiplyPointSimilarityInhomogenous(r0, 2, S, points_ring0, 2);
            MultiplyPointSimilarityInhomogenous(r0, 4, S, points_ring0, 4);
            MultiplyPointSimilarityInhomogenous(r0, 6, S, points_ring0, 6);
            MultiplyPointSimilarityInhomogenous(r0, 8, S, points_ring0, 8);
            MultiplyPointSimilarityInhomogenous(r0, 10, S, points_ring0, 10);

            // Locate ring 1 points
            MultiplyPointSimilarityInhomogenous(r1, 0, S, points_ring1, 0);
            MultiplyPointSimilarityInhomogenous(r1, 2, S, points_ring1, 2);
            MultiplyPointSimilarityInhomogenous(r1, 4, S, points_ring1, 4);
            MultiplyPointSimilarityInhomogenous(r1, 6, S, points_ring1, 6);
            MultiplyPointSimilarityInhomogenous(r1, 8, S, points_ring1, 8);
            MultiplyPointSimilarityInhomogenous(r1, 10, S, points_ring1, 10);

            // Locate ring 2 points
            MultiplyPointSimilarityInhomogenous(r2, 0, S, points_ring2, 0);
            MultiplyPointSimilarityInhomogenous(r2, 2, S, points_ring2, 2);
            MultiplyPointSimilarityInhomogenous(r2, 4, S, points_ring2, 4);
            MultiplyPointSimilarityInhomogenous(r2, 6, S, points_ring2, 6);
            MultiplyPointSimilarityInhomogenous(r2, 8, S, points_ring2, 8);
            MultiplyPointSimilarityInhomogenous(r2, 10, S, points_ring2, 10);

            // Locate ring 3 points
            MultiplyPointSimilarityInhomogenous(r3, 0, S, points_ring3, 0);
            MultiplyPointSimilarityInhomogenous(r3, 2, S, points_ring3, 2);
            MultiplyPointSimilarityInhomogenous(r3, 4, S, points_ring3, 4);
            MultiplyPointSimilarityInhomogenous(r3, 6, S, points_ring3, 6);
            MultiplyPointSimilarityInhomogenous(r3, 8, S, points_ring3, 8);
            MultiplyPointSimilarityInhomogenous(r3, 10, S, points_ring3, 10);

            // Locate ring 4 points
            MultiplyPointSimilarityInhomogenous(r4, 0, S, points_ring4, 0);
            MultiplyPointSimilarityInhomogenous(r4, 2, S, points_ring4, 2);
            MultiplyPointSimilarityInhomogenous(r4, 4, S, points_ring4, 4);
            MultiplyPointSimilarityInhomogenous(r4, 6, S, points_ring4, 6);
            MultiplyPointSimilarityInhomogenous(r4, 8, S, points_ring4, 8);
            MultiplyPointSimilarityInhomogenous(r4, 10, S, points_ring4, 10);

            // Locate ring 5 points
            MultiplyPointSimilarityInhomogenous(r5, 0, S, points_ring5, 0);
            MultiplyPointSimilarityInhomogenous(r5, 2, S, points_ring5, 2);
            MultiplyPointSimilarityInhomogenous(r5, 4, S, points_ring5, 4);
            MultiplyPointSimilarityInhomogenous(r5, 6, S, points_ring5, 6);
            MultiplyPointSimilarityInhomogenous(r5, 8, S, points_ring5, 8);
            MultiplyPointSimilarityInhomogenous(r5, 10, S, points_ring5, 10);

            // Transfer all the SIGMA values to the image
            sc = sigma_center * transform_scale;
            s0 = sigma_ring0 * transform_scale;
            s1 = sigma_ring1 * transform_scale;
            s2 = sigma_ring2 * transform_scale;
            s3 = sigma_ring3 * transform_scale;
            s4 = sigma_ring4 * transform_scale;
            s5 = sigma_ring5 * transform_scale;

            //
            // Locate and sample ring 5
            //
            GaussianScaleSpacePyramid.LocateResult lr = new GaussianScaleSpacePyramid.LocateResult();
            pyramid.locate(s5, lr);
            samples[0] = SampleReceptor(pyramid, r5[0], r5[1], lr.octave, lr.scale);
            samples[1] = SampleReceptor(pyramid, r5[2], r5[3], lr.octave, lr.scale);
            samples[2] = SampleReceptor(pyramid, r5[4], r5[5], lr.octave, lr.scale);
            samples[3] = SampleReceptor(pyramid, r5[6], r5[7], lr.octave, lr.scale);
            samples[4] = SampleReceptor(pyramid, r5[8], r5[9], lr.octave, lr.scale);
            samples[5] = SampleReceptor(pyramid, r5[10], r5[11], lr.octave,
                                        lr.scale);

            //
            // Locate and sample ring 4
            //

            pyramid.locate(s4, lr);
            samples[6]  = SampleReceptor(pyramid, r4[0], r4[1], lr.octave, lr.scale);
            samples[7]  = SampleReceptor(pyramid, r4[2], r4[3], lr.octave, lr.scale);
            samples[8]  = SampleReceptor(pyramid, r4[4], r4[5], lr.octave, lr.scale);
            samples[9]  = SampleReceptor(pyramid, r4[6], r4[7], lr.octave, lr.scale);
            samples[10] = SampleReceptor(pyramid, r4[8], r4[9], lr.octave, lr.scale);
            samples[11] = SampleReceptor(pyramid, r4[10], r4[11], lr.octave,
                                         lr.scale);

            //
            // Locate and sample ring 3
            //

            pyramid.locate(s3, lr);
            samples[12] = SampleReceptor(pyramid, r3[0], r3[1], lr.octave, lr.scale);
            samples[13] = SampleReceptor(pyramid, r3[2], r3[3], lr.octave, lr.scale);
            samples[14] = SampleReceptor(pyramid, r3[4], r3[5], lr.octave, lr.scale);
            samples[15] = SampleReceptor(pyramid, r3[6], r3[7], lr.octave, lr.scale);
            samples[16] = SampleReceptor(pyramid, r3[8], r3[9], lr.octave, lr.scale);
            samples[17] = SampleReceptor(pyramid, r3[10], r3[11], lr.octave,
                                         lr.scale);

            //
            // Locate and sample ring 2
            //

            pyramid.locate(s2, lr);
            samples[18] = SampleReceptor(pyramid, r2[0], r2[1], lr.octave, lr.scale);
            samples[19] = SampleReceptor(pyramid, r2[2], r2[3], lr.octave, lr.scale);
            samples[20] = SampleReceptor(pyramid, r2[4], r2[5], lr.octave, lr.scale);
            samples[21] = SampleReceptor(pyramid, r2[6], r2[7], lr.octave, lr.scale);
            samples[22] = SampleReceptor(pyramid, r2[8], r2[9], lr.octave, lr.scale);
            samples[23] = SampleReceptor(pyramid, r2[10], r2[11], lr.octave,
                                         lr.scale);

            //
            // Locate and sample ring 1
            //

            pyramid.locate(s1, lr);
            samples[24] = SampleReceptor(pyramid, r1[0], r1[1], lr.octave, lr.scale);
            samples[25] = SampleReceptor(pyramid, r1[2], r1[3], lr.octave, lr.scale);
            samples[26] = SampleReceptor(pyramid, r1[4], r1[5], lr.octave, lr.scale);
            samples[27] = SampleReceptor(pyramid, r1[6], r1[7], lr.octave, lr.scale);
            samples[28] = SampleReceptor(pyramid, r1[8], r1[9], lr.octave, lr.scale);
            samples[29] = SampleReceptor(pyramid, r1[10], r1[11], lr.octave, lr.scale);

            //
            // Locate and sample ring 0
            //

            pyramid.locate(s0, lr);
            samples[30] = SampleReceptor(pyramid, r0[0], r0[1], lr.octave, lr.scale);
            samples[31] = SampleReceptor(pyramid, r0[2], r0[3], lr.octave, lr.scale);
            samples[32] = SampleReceptor(pyramid, r0[4], r0[5], lr.octave, lr.scale);
            samples[33] = SampleReceptor(pyramid, r0[6], r0[7], lr.octave, lr.scale);
            samples[34] = SampleReceptor(pyramid, r0[8], r0[9], lr.octave, lr.scale);
            samples[35] = SampleReceptor(pyramid, r0[10], r0[11], lr.octave,
                                         lr.scale);

            //
            // Locate and sample center
            //

            pyramid.locate(sc, lr);
            samples[36] = SampleReceptor(pyramid, c[0], c[1], lr.octave, lr.scale);

            return(true);
        }
        // private boolean ComputeSubpixelHessian(
        // float H[9],float b[3],
        // const Image& lap0,const Image& lap1,const Image& lap2,
        // int x,int y)

        private bool updateLocation(DogFeaturePoint kp, LaplacianImage lap0, LaplacianImage lap1, LaplacianImage lap2)
        {
            double[] tmp = new double[2];
            double[] b   = new double[3];


            // Downsample the feature point to the detection octave
            bilinear_downsample_point(tmp, kp.x, kp.y, kp.octave);
            double xp = tmp[0];
            double yp = tmp[1];
            // Compute the discrete pixel location
            int x = (int)(xp + 0.5f);
            int y = (int)(yp + 0.5f);

            double[] H = new double[9];
            if (lap0.getWidth() == lap1.getWidth() && lap1.getWidth() == lap2.getWidth())
            {
                //すべての画像サイズが同じ
                //assert lap0.getHeight() == lap1.getHeight() && lap1.getHeight() == lap2.getHeight();// "Width/height are not consistent");
                ComputeSubpixelHessianSameOctave(H, b, lap0, lap1, lap2, x, y);
            }
            else if ((lap0.getWidth() == lap1.getWidth()) && ((lap1.getWidth() >> 1) == lap2.getWidth()))
            {
                //0,1が同じで2がその半分
                //assert (lap0.getHeight() == lap1.getHeight()) && ((lap1.getHeight() >> 1) == lap2.getHeight());// Width/height are not consistent");
                ComputeSubpixelHessianFineOctavePair(H, b, lap0, lap1, lap2, x, y);
            }
            else if (((lap0.getWidth() >> 1) == lap1.getWidth()) && (lap1.getWidth() == lap2.getWidth()))
            {
                //0の半分が1,2
                //assert ((lap0.getWidth() >> 1) == lap1.getWidth()) && (lap1.getWidth() == lap2.getWidth());// Width/height are not consistent");
                ComputeSubpixelHessianCoarseOctavePair(H, b, lap0, lap1, lap2, x, y);
            }
            else
            {
                // ASSERT(0, "Image sizes are inconsistent");
                return(false);
            }

            // A*u=b	//		if (!SolveSymmetricLinearSystem3x3(u, H, b)) {
            NyARDoubleMatrix33 m = new NyARDoubleMatrix33();

            m.m00 = H[0];
            m.m01 = H[1];
            m.m02 = H[2];
            m.m10 = H[3];
            m.m11 = H[4];
            m.m12 = H[5];
            m.m20 = H[6];
            m.m21 = H[7];
            m.m22 = H[8];
            if (!m.inverse(m))
            {
                return(false);
            }
            double u0 = (m.m00 * b[0] + m.m01 * b[1] + m.m02 * b[2]);
            double u1 = (m.m10 * b[0] + m.m11 * b[1] + m.m12 * b[2]);
            double u2 = (m.m20 * b[0] + m.m21 * b[1] + m.m22 * b[2]);


            // If points move too much in the sub-pixel update, then the point probably unstable.
            if ((u0 * u0) + (u1 * u1) > mMaxSubpixelDistanceSqr)
            {
                return(false);
            }

            // Compute the edge score
            if (!ComputeEdgeScore(tmp, H))
            {
                return(false);
            }
            kp.edge_score = tmp[0];

            // Compute a linear estimate of the intensity
            // ASSERT(kp.score == lap1.get<float>(y)[x],
            // "Score is not consistent with the DoG image");
            double[] lap1_buf = (double[])lap1.getBuffer();
            kp.score = lap1_buf[lap1.get(y) + x] - (b[0] * u0 + b[1] * u1 + b[2] * u2);

            // Update the location:
            // Apply the update on the downsampled location and then upsample
            // the result.
            // bilinear_upsample_point(kp.x, kp.y, xp+u[0], yp+u[1], kp.octave);
            bilinear_upsample_point(tmp, xp + u0, yp + u1, kp.octave);
            kp.x = tmp[0];
            kp.y = tmp[1];

            // Update the scale
            kp.sp_scale = kp.scale + u2;
            kp.sp_scale = ClipScalar(kp.sp_scale, 0, mLaplacianPyramid.numScalePerOctave());
            return(true);
        }
        /**
         * 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;
        }