/** * 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); }
/** * 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]); } }
/** * 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; }