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

boofcv.alg.tracker.tld.TldTemplateMatching Maven / Gradle / Ivy

/*
 * 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.tracker.tld;

import boofcv.alg.descriptor.DescriptorDistance;
import boofcv.alg.interpolate.InterpolatePixelS;
import boofcv.struct.ImageRectangle;
import boofcv.struct.feature.NccFeature;
import boofcv.struct.image.ImageGray;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;

/**
 * Created {@link NccFeature NCC} templates to describe the target region. Each template is composed of a 15x15
 * area. The descriptor is computed by sampling evenly spaced points through out the rectangular region. Confidence
 * values are computed based in the distance a point is from the closest positive and negative template.
 *
 * @author Peter Abeles
 */
@SuppressWarnings({"NullAway.Init"})
public class TldTemplateMatching> {

	// set of features for positive and negative examples
	private List templatePositive = new ArrayList<>();
	private List templateNegative = new ArrayList<>();

	// storage for the feature in the region that's being processed.
	private NccFeature observed = new NccFeature(15*15);

	// used when sampling the image
	private InterpolatePixelS interpolate;

	// storage for descriptors which can be recycled
	protected ArrayDeque unused = new ArrayDeque<>();

	public TldTemplateMatching( InterpolatePixelS interpolate ) {
		this.interpolate = interpolate;
	}

	protected TldTemplateMatching() {}

	/**
	 * Discard previous results and puts it back into its initial state
	 */
	public void reset() {
		unused.addAll(templateNegative);
		unused.addAll(templatePositive);
		templateNegative.clear();
		templatePositive.clear();
	}

	/**
	 * Must call this function before any of the others which process descriptions
	 *
	 * @param gray Input image
	 */
	public void setImage( T gray ) {
		interpolate.setImage(gray);
	}

	/**
	 * Creates a new descriptor for the specified region
	 *
	 * @param positive if it is a positive or negative example
	 */
	public void addDescriptor( boolean positive, ImageRectangle rect ) {
		addDescriptor(positive, rect.x0, rect.y0, rect.x1, rect.y1);
	}

	public void addDescriptor( boolean positive, float x0, float y0, float x1, float y1 ) {

		NccFeature f = createDescriptor();
		computeNccDescriptor(f, x0, y0, x1, y1);
		addDescriptor(positive, f);
	}

	/**
	 * Adds a descriptor to the positive or negative list. If it is very similar to an existing one it is not
	 * added. Look at code for details
	 *
	 * @param positive true for positive list and false for negative list
	 * @param f The feature which is to be added
	 */
	private void addDescriptor( boolean positive, NccFeature f ) {
		// avoid adding the same descriptor twice or adding contradicting results
		if (positive)
			if (distance(f, templatePositive) < 0.05) {
				return;
			}
		if (!positive) {
			if (distance(f, templateNegative) < 0.05) {
				return;
			}
			// a positive positive can have very bad affects on tracking, try to avoid learning a positive
			// example as a negative one
			if (distance(f, templatePositive) < 0.05) {
				return;
			}
		}

		if (positive)
			templatePositive.add(f);
		else
			templateNegative.add(f);
	}

	/**
	 * Computes the NCC descriptor by sample points at evenly spaced distances inside the rectangle
	 */
	public void computeNccDescriptor( NccFeature f, float x0, float y0, float x1, float y1 ) {
		double mean = 0;
		float widthStep = (x1 - x0)/15.0f;
		float heightStep = (y1 - y0)/15.0f;

		// compute the mean value
		int index = 0;
		for (int y = 0; y < 15; y++) {
			float sampleY = y0 + y*heightStep;
			for (int x = 0; x < 15; x++) {
				mean += f.data[index++] = interpolate.get_fast(x0 + x*widthStep, sampleY);
			}
		}
		mean /= 15*15;

		// compute the variance and save the difference from the mean
		double variance = 0;
		index = 0;
		for (int y = 0; y < 15; y++) {
			for (int x = 0; x < 15; x++) {
				double v = f.data[index++] -= mean;
				variance += v*v;
			}
		}
		variance /= 15*15;
		f.mean = mean;
		f.sigma = Math.sqrt(variance);
	}

	/**
	 * Creates a new descriptor or recycles an old one
	 */
	public NccFeature createDescriptor() {
		NccFeature f;
		if (unused.isEmpty())
			f = new NccFeature(15*15);
		else
			f = unused.pop();
		return f;
	}

	/**
	 * Compute a value which indicates how confident the specified region is to be a member of the positive set.
	 * The confidence value is from 0 to 1. 1 indicates 100% confidence.
	 *
	 * Positive and negative templates are used to compute the confidence value. Only the point in each set
	 * which is closest to the specified region are used in the calculation.
	 *
	 * @return value from 0 to 1, where higher values are more confident
	 */
	public double computeConfidence( int x0, int y0, int x1, int y1 ) {

		computeNccDescriptor(observed, x0, y0, x1, y1);

		// distance from each set of templates
		if (templateNegative.size() > 0 && templatePositive.size() > 0) {
			double distancePositive = distance(observed, templatePositive);
			double distanceNegative = distance(observed, templateNegative);

			return distanceNegative/(distanceNegative + distancePositive);
		} else if (templatePositive.size() > 0) {
			return 1.0 - distance(observed, templatePositive);
		} else {
			return distance(observed, templateNegative);
		}
	}

	/**
	 * see the other function with the same name
	 */
	public double computeConfidence( ImageRectangle r ) {
		return computeConfidence(r.x0, r.y0, r.x1, r.y1);
	}

	/**
	 * Computes the best distance to 'observed' from the candidate list.
	 *
	 * @param observed Feature being matched
	 * @param candidates Set of candidate matches
	 * @return score from 0 to 1, where lower is closer
	 */
	public double distance( NccFeature observed, List candidates ) {

		double maximum = -Double.MAX_VALUE;

		// The feature which has the best fit will maximize the score
		for (int featIdx = 0; featIdx < candidates.size(); featIdx++) {
			NccFeature f = candidates.get(featIdx);
			double score = DescriptorDistance.ncc(observed, f);
			if (score > maximum)
				maximum = score;
		}

		return 1 - 0.5*(maximum + 1);
	}

	public List getTemplatePositive() {
		return templatePositive;
	}

	public List getTemplateNegative() {
		return templateNegative;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy