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

boofcv.alg.feature.detdesc.CompleteSift 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.detdesc;

import boofcv.alg.feature.describe.DescribePointSift;
import boofcv.alg.feature.detect.interest.SiftDetector;
import boofcv.alg.feature.detect.interest.SiftDetector.SiftPoint;
import boofcv.alg.feature.detect.interest.SiftScaleSpace;
import boofcv.alg.feature.detect.interest.UnrollSiftScaleSpaceGradient;
import boofcv.alg.feature.orientation.OrientationHistogramSift;
import boofcv.struct.feature.ScalePoint;
import boofcv.struct.feature.TupleDesc_F64;
import boofcv.struct.image.GrayF32;
import lombok.Getter;
import org.ddogleg.struct.DogArray;
import org.ddogleg.struct.DogArray_F64;
import org.ddogleg.struct.FastAccess;
import org.ddogleg.struct.FastArray;

import java.util.List;

/**
 * SIFT combined together to simultaneously detect and describe the key points it finds. Memory is conserved by
 * only having one octave of the scale-space in memory at any given time.
 *
 * @author Peter Abeles
 * @see OrientationHistogramSift
 * @see DescribePointSift
 * @see SiftDetector
 */
public class CompleteSift {
	@Getter SiftScaleSpace scaleSpace;
	// Detects SIFT features
	@Getter SiftDetector detector;
	// estimate orientation
	@Getter OrientationHistogramSift orientation;
	// describes the keypoints
	@Getter DescribePointSift describe;
	// storage for found features
	DogArray features;
	// found orientations and feature locations
	FastArray locations = new FastArray<>(ScalePoint.class);
	@Getter DogArray_F64 orientations = new DogArray_F64();

	UnrollSiftScaleSpaceGradient gradient = new UnrollSiftScaleSpaceGradient();

	/**
	 * Configures SIFT
	 *
	 * @param detector Feature detector
	 * @param orientation Estimates feature orientation(s)
	 * @param describe Describes a SIFT feature
	 */
	public CompleteSift( SiftScaleSpace scaleSpace,
						 SiftDetector detector,
						 OrientationHistogramSift orientation,
						 DescribePointSift describe ) {
		this.scaleSpace = scaleSpace;
		this.detector = detector;
		this.orientation = orientation;
		this.describe = describe;

		final int dof = describe.getDescriptorLength();
		features = new DogArray<>(() -> new TupleDesc_F64(dof));
		gradient.initialize(scaleSpace);
	}

	/**
	 * Detects features inside the image and computes descriptors
	 */
	public void process( GrayF32 input ) {
		// Clear previous results
		features.reset();
		locations.reset();
		orientations.reset();

		// Compute the scale space
		scaleSpace.process(input);

		// Detect features
		detector.process(scaleSpace);

		// Precompute gradient
		gradient.process(scaleSpace);

		// Describe every point
		List detections = detector.getDetections();
		describeDetections(detections);
	}

	/**
	 * Computes one or more descriptors for every point in the passed in list
	 */
	protected void describeDetections( List detections ) {
		for (int detIdx = 0; detIdx < detections.size(); detIdx++) {
			SiftPoint p = detections.get(detIdx);

			// Would it be faster if all features that come from the same images were processed at once?
			// Would it reduce context switching?

			// Gradient image is offset by one
			GrayF32 derivX = gradient.getDerivX(p.octaveIdx, (byte)(p.scaleIdx - 1));
			GrayF32 derivY = gradient.getDerivY(p.octaveIdx, (byte)(p.scaleIdx - 1));

			orientation.setImageGradient(derivX, derivY);
			describe.setImageGradient(derivX, derivY);

			double pixelScaleToInput = scaleSpace.pixelScaleCurrentToInput(p.octaveIdx);

			// adjust the image for the down sampling in each octave
			double localX = p.pixel.x/pixelScaleToInput;
			double localY = p.pixel.y/pixelScaleToInput;
			double localSigma = p.scale/pixelScaleToInput;

			// find potential orientations first
			orientation.process(localX, localY, localSigma);

			// describe each feature
			DogArray_F64 angles = orientation.getOrientations();
			for (int angleIdx = 0; angleIdx < angles.size; angleIdx++) {
				describe.process(localX, localY, localSigma, angles.get(angleIdx), features.grow());
				orientations.add(angles.get(angleIdx));
				locations.add(p);
			}
		}
	}

	public FastAccess getLocations() {
		return locations;
	}

	public FastAccess getDescriptions() {
		return features;
	}

	public int getDescriptorLength() {
		return describe.getDescriptorLength();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy