public DoGScaleInvariantDetector(int i_width, int i_height, int i_octerv, int i_num_of_scale_of_octerv, double i_LaplacianThreshold,
                                  double i_EdgeThreshold, int i_MaxNumFeaturePoints)
 {
     this.mLaplacianThreshold     = i_LaplacianThreshold;
     this.mEdgeThreshold          = i_EdgeThreshold;
     this.mMaxSubpixelDistanceSqr = (3 * 3);
     this.mOrientations           = new double[kMaxNumOrientations];
     this.mLaplacianPyramid       = new DoGPyramid(i_width, i_height, i_octerv, i_num_of_scale_of_octerv - 1);
     this.mOrientationAssignment  = new OrientationAssignment(i_width, i_height, i_octerv, i_num_of_scale_of_octerv, kMaxNumOrientations, 3, 1.5f, 5, 0.8f);
     this.mBuckets = new AreaBuckit(i_width, i_height, 10, 10, i_MaxNumFeaturePoints);
     this._tmp_fps = new DogFeaturePointStack(kMaxNumFeaturePoints);
 }
        /**
         * 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;
        }