All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.alg.feature.orientation.impl.ImplOrientationSlidingWindowIntegral Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

The newest version!
/*
 * Copyright (c) 2021, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.feature.orientation.impl;

import boofcv.abst.feature.orientation.RegionOrientation;
import boofcv.alg.feature.orientation.OrientationIntegralBase;
import boofcv.struct.image.ImageGray;
import boofcv.struct.sparse.GradientValue;
import georegression.metric.UtilAngle;
import org.ddogleg.sorting.QuickSort_F64;

/**
 * 

* Implementation of {@link boofcv.alg.feature.orientation.OrientationSlidingWindow} for integral images. * TODO comment how this implementation works *

* * @author Peter Abeles */ public class ImplOrientationSlidingWindowIntegral, G extends GradientValue> extends OrientationIntegralBase { // where the output from the derivative is stored double[] derivX; double[] derivY; // the size of the angle window it will consider in radians protected double windowSize; // the angle each pixel is pointing protected double[] angles; // clockwise ordering of angles protected int[] order; int total = 0; QuickSort_F64 sorter = new QuickSort_F64(); /** * Specifies configuration parameters and initializes data structures * * @param samplePeriod How often the image is sampled. This number is scaled. Typically 1. * @param windowSize Angular window that is slide across * @param sampleRadius Radius of the region being considered in terms of samples. Typically 6. * @param weightSigma Sigma for weighting distribution. Zero for unweighted. * @param sampleKernelWidth Size of kernel doing the sampling. Typically 4. * @param integralType Type of integral image being processed. */ public ImplOrientationSlidingWindowIntegral( double radiusToScale, double samplePeriod, double windowSize, int sampleRadius, double weightSigma, int sampleKernelWidth, Class integralType ) { super(radiusToScale, sampleRadius, samplePeriod, sampleKernelWidth, weightSigma, true, integralType); this.windowSize = windowSize; derivX = new double[sampleWidth*sampleWidth]; derivY = new double[sampleWidth*sampleWidth]; angles = new double[sampleWidth*sampleWidth]; order = new int[angles.length]; } @Override public double compute( double c_x, double c_y ) { double period = scale*this.period; // top left corner of the region being sampled double tl_x = c_x - sampleRadius*period; double tl_y = c_y - sampleRadius*period; computeGradient(tl_x, tl_y, period); // apply weight to each gradient dependent on its position if (weights != null) { for (int i = 0; i < total; i++) { double w = weights.data[i]; derivX[i] *= w; derivY[i] *= w; } } for (int i = 0; i < total; i++) { angles[i] = Math.atan2(derivY[i], derivX[i]); } // order points from lowest to highest sorter.sort(angles, 0, angles.length, order); return estimateAngle(); } private void computeGradient( double tl_x, double tl_y, double samplePeriod ) { // add 0.5 to c_x and c_y to have it round when converted to an integer pixel // this is faster than the straight forward method tl_x += 0.5; tl_y += 0.5; total = 0; for (int y = 0; y < sampleWidth; y++) { for (int x = 0; x < sampleWidth; x++, total++) { int xx = (int)(tl_x + x*samplePeriod); int yy = (int)(tl_y + y*samplePeriod); if (g.isInBounds(xx, yy)) { GradientValue deriv = g.compute(xx, yy); double dx = deriv.getX(); double dy = deriv.getY(); derivX[total] = dx; derivY[total] = dy; } else { derivX[total] = 0; derivY[total] = 0; } } } } private double estimateAngle() { int start = 0; int end = 1; int startIndex = order[start]; int endIndex = order[end]; double sumX = derivX[startIndex]; double sumY = derivY[startIndex]; double best = sumX*sumX + sumY*sumY; double bestX = sumX; double bestY = sumY; double endAngle = angles[endIndex]; while (start != total) { startIndex = order[start]; double startAngle = angles[startIndex]; // only compute the average if the angles are close to each other while (UtilAngle.dist(startAngle, endAngle) <= windowSize) { sumX += derivX[endIndex]; sumY += derivY[endIndex]; // see if the magnitude of the gradient inside this bound is greater // than the previous best double mag = sumX*sumX + sumY*sumY; if (mag > best) { best = mag; bestX = sumX; bestY = sumY; } end++; if (end >= total) end = 0; endIndex = order[end]; endAngle = angles[endIndex]; // if it cycled all the way around stop if (endIndex == startIndex) break; } // remove the first element from the list sumX -= derivX[startIndex]; sumY -= derivY[startIndex]; start++; } return Math.atan2(bestY, bestX); } @Override public RegionOrientation copy() { return new ImplOrientationSlidingWindowIntegral( objectRadiusToScale, period, windowSize, sampleRadius, weightSigma, kernelWidth, getImageType()); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy