View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.image.model.landmark;
31  
32  import org.openimaj.image.FImage;
33  import org.openimaj.image.pixel.sampling.FLineSampler;
34  import org.openimaj.image.pixel.statistics.FStatisticalPixelProfileModel;
35  import org.openimaj.image.pixel.statistics.PixelProfileModel;
36  import org.openimaj.math.geometry.line.Line2d;
37  import org.openimaj.math.geometry.point.Point2d;
38  import org.openimaj.math.geometry.point.PointList;
39  import org.openimaj.math.geometry.point.PointListConnections;
40  import org.openimaj.util.pair.ObjectFloatPair;
41  
42  /**
43   * An {@link FNormalLandmarkModel} is a landmark represented by the 
44   * surface normal line of a point (which is usually part of a 
45   * {@link PointList} in an {@link FImage} connected by {@link PointListConnections}). 
46   * 
47   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
48   */
49  public class FNormalLandmarkModel implements LandmarkModel<FImage> {
50  	/**
51  	 * A factory for producing {@link FNormalLandmarkModel}s
52  	 * 
53  	 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
54  	 */
55  	public static class Factory implements LandmarkModelFactory<FImage> {
56  		private PointListConnections connections;
57  		private float normalLength;
58  		private int numSearchSamples;
59  		private FLineSampler sampler;
60  		private int numModelSamples;
61  
62  		/**
63  		 * Default constructor.
64  		 * @param connections connections between points.
65  		 * @param sampler sampler for sampling along normals 
66  		 * @param numModelSamples number of samples for the model
67  		 * @param numSearchSamples number of samples for search; must be bigger than numModelSamples
68  		 * @param normalLength length of the normal in intrinsic scale units
69  		 */
70  		public Factory(PointListConnections connections, FLineSampler sampler, int numModelSamples, int numSearchSamples, float normalLength) {
71  			this.connections = connections;
72  			this.sampler = sampler;
73  			this.numModelSamples = numModelSamples;
74  			this.normalLength = normalLength;
75  			this.numSearchSamples = numSearchSamples;
76  		}
77  
78  		@Override
79  		public FNormalLandmarkModel createLandmarkModel() {
80  			return new FNormalLandmarkModel(connections, sampler, numModelSamples, numSearchSamples, normalLength);
81  		}
82  		
83  		@Override
84  		public FNormalLandmarkModel createLandmarkModel(float scaleFactor) {
85  			return new FNormalLandmarkModel(connections, sampler, numModelSamples, numSearchSamples, scaleFactor * normalLength);
86  		}
87  	}
88  
89  	private PointListConnections connections;
90  	private PixelProfileModel<FImage> model;
91  	private float normalLength;
92  	private int numModelSamples;
93  	private int numSearchSamples;
94  
95  	/**
96  	 * Default constructor.
97  	 * 
98  	 * @param connections connections between points.
99  	 * @param sampler sampler for sampling along normals 
100 	 * @param numModelSamples number of samples for the model
101 	 * @param numSearchSamples number of samples for search; must be bigger than numModelSamples
102 	 * @param normalLength length of the normal in intrinsic scale units
103 	 */
104 	public FNormalLandmarkModel(PointListConnections connections, FLineSampler sampler, int numModelSamples, int numSearchSamples, float normalLength) {
105 		this.connections = connections;
106 		this.model = new FStatisticalPixelProfileModel(numModelSamples, sampler);
107 		this.normalLength = normalLength;
108 		this.numModelSamples = numModelSamples;
109 		this.numSearchSamples = numSearchSamples;
110 	}
111 
112 	@Override
113 	public void updateModel(FImage image, Point2d point, PointList pointList) {
114 		float lineScale = normalLength * pointList.computeIntrinsicScale();
115 		Line2d line = connections.calculateNormalLine(point, pointList, lineScale);
116 		
117 		model.updateModel(image, line);
118 	}
119 
120 	@Override
121 	public float computeCost(FImage image, Point2d point, PointList pointList) {
122 		float lineScale = normalLength * pointList.computeIntrinsicScale();
123 		Line2d line = connections.calculateNormalLine(point, pointList, lineScale);
124 
125 		return model.computeCost(image, line);
126 	}
127 
128 	@Override
129 	public ObjectFloatPair<Point2d> updatePosition(FImage image, Point2d initial, PointList pointList) {
130 		float scale = numSearchSamples * normalLength * pointList.computeIntrinsicScale() / (float) numModelSamples;
131 		Line2d line = connections.calculateNormalLine(initial, pointList, scale);
132 		
133 		Point2d newBest = model.computeNewBest(image, line, numSearchSamples);
134 		float distance = model.computeMovementDistance(image, line, numSearchSamples, newBest);
135 		
136 		return new ObjectFloatPair<Point2d>(newBest, distance);
137 	}
138 }