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

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

Go to download

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

There is a newer version: 0.26
Show newest version
/*
 * Copyright (c) 2011-2016, 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.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 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
 */
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 Stack unused = new Stack();

	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.value[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.value[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( NccFeature f : candidates ) {
			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 - 2025 Weber Informatics LLC | Privacy Policy