001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image.model.landmark; 031 032import org.openimaj.image.FImage; 033import org.openimaj.image.analysis.algorithm.TemplateMatcher; 034import org.openimaj.image.analysis.algorithm.TemplateMatcher.Mode; 035import org.openimaj.image.pixel.FValuePixel; 036import org.openimaj.math.geometry.point.Point2d; 037import org.openimaj.math.geometry.point.PointList; 038import org.openimaj.math.geometry.shape.Rectangle; 039import org.openimaj.util.pair.ObjectFloatPair; 040 041/** 042 * An {@link FPatchLandmarkModel} is a landmark represented by the 043 * local patch of pixels around of a point in an {@link FImage}. 044 * 045 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 046 */ 047public class FPatchLandmarkModel implements LandmarkModel<FImage> { 048 /** 049 * A factory for producing {@link FPatchLandmarkModel}s 050 * 051 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 052 */ 053 public static class Factory implements LandmarkModelFactory<FImage> { 054 @Override 055 public LandmarkModel<FImage> createLandmarkModel() { 056 return new FPatchLandmarkModel(); 057 } 058 059 @Override 060 public LandmarkModel<FImage> createLandmarkModel(float scaleFactor) { 061 return new FPatchLandmarkModel(); 062 } 063 } 064 065 int blockSize = 11; 066 int searchSize = 31; 067 068 FImage average; 069 int n = 0; 070 TemplateMatcher matcher; 071 072 protected Rectangle getROI(int x, int y, int w, int h) { 073 if(w % 2 == 0 ) w+=1; 074 if(h % 2 == 0 ) h+=1; 075 076 int roiX = Math.max(0,x-(int)(w/2.0)); 077 int roiY = Math.max(0,y-(int)(h/2.0)); 078 079 int newWidth = (int)(w / 2.0) + 1 + (x - roiX); 080 int newHeight = (int)(h / 2.0) + 1 + (y - roiY); 081 082 return new Rectangle(roiX, roiY, newWidth, newHeight); 083 } 084 085 protected FImage extractBlock(FImage image, Point2d pt, int sz) { 086 return image.extractROI(getROI((int)pt.getX(), (int)pt.getY(), sz, sz)); 087 } 088 089 @Override 090 public void updateModel(FImage image, Point2d point, PointList pointList) { 091 FImage extracted = extractBlock(image, point, blockSize); 092 093 n++; 094 if (average == null) { 095 average = extracted; 096 } else { 097 average.addInplace( extracted.subtractInplace(average).divide((float)n) ); 098 } 099 matcher = null; 100 } 101 102 @Override 103 public float computeCost(FImage image, Point2d point, PointList pointList) { 104 FImage extracted = extractBlock(image, point, blockSize); 105 106 if (matcher == null) 107 matcher = new TemplateMatcher(average, Mode.NORM_SUM_SQUARED_DIFFERENCE); 108 109 matcher.setSearchBounds(null); 110 extracted.analyseWith(matcher); 111 112 return matcher.getResponseMap().pixels[0][0]; 113 } 114 115 @Override 116 public ObjectFloatPair<Point2d> updatePosition(FImage image, Point2d initial, PointList pointList) { 117 Rectangle roi = getROI((int)initial.getX(), (int)initial.getY(), searchSize, searchSize); 118 119 if (matcher == null) 120 matcher = new TemplateMatcher(average, Mode.NORM_SUM_SQUARED_DIFFERENCE); 121 122 matcher.setSearchBounds(roi); 123 image.analyseWith(matcher); 124 FValuePixel p = matcher.getBestResponses(1)[0]; 125 126 return new ObjectFloatPair<Point2d>(p, 0); 127 } 128}