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

org.openimaj.image.analysis.algorithm.TemplateMatcher Maven / Gradle / Ivy

/**
 * Copyright (c) 2011, The University of Southampton and the individual contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *   * 	Redistributions of source code must retain the above copyright notice,
 * 	this list of conditions and the following disclaimer.
 *
 *   *	Redistributions in binary form must reproduce the above copyright notice,
 * 	this list of conditions and the following disclaimer in the documentation
 * 	and/or other materials provided with the distribution.
 *
 *   *	Neither the name of the University of Southampton nor the names of its
 * 	contributors may be used to endorse or promote products derived from this
 * 	software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.openimaj.image.analysis.algorithm;

import java.io.File;
import java.io.IOException;
import java.util.Comparator;

import org.openimaj.image.DisplayUtilities;
import org.openimaj.image.FImage;
import org.openimaj.image.ImageUtilities;
import org.openimaj.image.MBFImage;
import org.openimaj.image.analyser.ImageAnalyser;
import org.openimaj.image.colour.RGBColour;
import org.openimaj.image.pixel.FValuePixel;
import org.openimaj.image.processing.algorithm.MeanCenter;
import org.openimaj.math.geometry.shape.Rectangle;
import org.openimaj.util.queue.BoundedPriorityQueue;

/**
 * Basic template matching for {@link FImage}s. Template matching is
 * performed in the spatial domain.
 *
 * @author Jonathon Hare ([email protected])
 */
public class TemplateMatcher implements ImageAnalyser {
	/**
	 * Different algorithms for comparing templates to images.
	 *
	 * @author Jonathon Hare ([email protected])
	 */
	public enum Mode {
		/**
		 * Compute the score at a point as the sum-squared difference between the image
		 * and the template with the top-left at the given point. The {@link TemplateMatcher}
		 * will account for the offset to the centre of the template internally.
		 *
		 * @author Jonathon Hare ([email protected])
		 */
		SUM_SQUARED_DIFFERENCE {
			@Override
			protected float computeMatchScore(final FImage image, final FImage template, final int x, final int y, final Object workingSpace) {
				final float[][] imageData = image.pixels;
				final float[][] templateData = template.pixels;

				return computeMatchScore(imageData, x, y, templateData, 0, 0, template.width, template.height);
			}

			@Override
			public final float computeMatchScore(final float[][] img, int x, int y, final float[][] template, final int templateX, final int templateY, final int templateWidth, final int templateHeight) {
				final int stopX1 = templateWidth + x;
				final int stopY1 = templateHeight + y;
				final int stopX2 = templateWidth + templateX;
				final int stopY2 = templateHeight + templateY;

				float score = 0;
				for (int yy1=y, yy2=templateY; yy1null results in the entire image
	 * being searched.
	 *
	 * @param searchBounds the search bounds to set
	 */
	public void setSearchBounds(Rectangle searchBounds) {
		this.searchBounds = searchBounds;
	}

	/**
	 * Perform template matching. If a bounds rectangle
	 * is has not been set or is null, then the whole
	 * image will be searched. Otherwise the area of the image
	 * which lies in the previously set search bounds will be
	 * searched.
	 *
	 * @see org.openimaj.image.analyser.ImageAnalyser#analyseImage(org.openimaj.image.Image)
	 */
	@Override
	public void analyseImage(FImage image) {
		Rectangle searchSpace = null;

		if (this.searchBounds != null) {
			final int halfWidth = template.width / 2;
			final int halfHeight = template.height / 2;

			float x = Math.max(searchBounds.x - halfWidth, 0);
			x = Math.min(x, image.width-template.width);
			float width = searchBounds.width;
			if (searchBounds.x - halfWidth < 0) {
				width += (searchBounds.x - halfWidth);
			}
			if (x + width > image.width - template.width)
				width += (image.width - template.width) - (x+width);

			float y = Math.max(searchBounds.y - halfHeight, 0);
			y = Math.min(y, image.height - template.height);
			float height = searchBounds.height;
			if (searchBounds.y - halfHeight < 0) {
				height += (searchBounds.y - halfHeight);
			}
			if (y + height > image.height - template.height)
				height += (image.height - template.height) - (y+height);

			searchSpace = new Rectangle(
					x,
					y,
					width,
					height
			);

		} else {
			searchSpace = new Rectangle(
					0,
					0,
					image.width - template.width + 1,
					image.height - template.height + 1
			);
		}

		final int scanX = (int) searchSpace.x;
		final int scanY = (int) searchSpace.y;
		final int scanWidth = (int)searchSpace.width;
		final int scanHeight = (int)searchSpace.height;

		responseMap = new FImage(scanWidth, scanHeight);
		final float[][] responseMapData = responseMap.pixels;

		for (int y=0; y comparator = mode.scoresAscending() ? FValuePixel.ReverseValueComparator.INSTANCE : FValuePixel.ValueComparator.INSTANCE;

		return getBestResponses(numResponses, responseMap, getXOffset(), getYOffset(), comparator);
	}

	/**
	 * Get the top-N "best" responses found by the template matcher.
	 *
	 * @param numResponses The number of responses
	 * @param responseMap The response map
	 * @param offsetX the amount to shift pixels in the x direction
	 * @param offsetY the amount to shift pixels in the y direction
	 * @param comparator the comparator for determining the "best" responses
	 * @return the best responses found
	 */
	public static FValuePixel[] getBestResponses(int numResponses, FImage responseMap, int offsetX, int offsetY, Comparator comparator) {
		BoundedPriorityQueue bestResponses = new BoundedPriorityQueue(numResponses, comparator);

		final float[][] responseMapData = responseMap.pixels;

		final int scanWidth = responseMap.width;
		final int scanHeight = responseMap.height;

		FValuePixel tmpPixel = new FValuePixel(0, 0, 0);
		for (int y=0; y




© 2015 - 2024 Weber Informatics LLC | Privacy Policy