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.feature.dense.binarypattern;
31  
32  import org.openimaj.citation.annotation.Reference;
33  import org.openimaj.citation.annotation.ReferenceType;
34  import org.openimaj.image.FImage;
35  import org.openimaj.image.analyser.ImageAnalyser;
36  import org.openimaj.image.pixel.Pixel;
37  
38  /**
39   * Implementation of a Local Ternary Pattern.
40   * 
41   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
42   */
43  @Reference(
44  		type = ReferenceType.Article,
45  		author = { "Tan, Xiaoyang", "Triggs, Bill" },
46  		title = "Enhanced local texture feature sets for face recognition under difficult lighting conditions",
47  		year = "2010",
48  		journal = "Trans. Img. Proc.",
49  		pages = { "1635", "", "1650" },
50  		url = "http://dx.doi.org/10.1109/TIP.2010.2042645",
51  		month = "June",
52  		number = "6",
53  		publisher = "IEEE Press",
54  		volume = "19"
55  	)
56  public class LocalTernaryPattern implements ImageAnalyser<FImage> {
57  	protected int[][] positiveBinaryPattern;
58  	protected int[][] negativeBinaryPattern;
59  	protected int[][] ternaryPattern;
60  	
61  	protected float radius;
62  	protected int samples;
63  	protected float threshold;
64  	
65  	/**
66  	 * Construct an LTP extractor with the given parameters.
67  	 * @param radius the radius of the sampling circle
68  	 * @param samples the number of samples around the circle
69  	 * @param threshold the threshold
70  	 */
71  	public LocalTernaryPattern(float radius, int samples, float threshold) {
72  		checkParams(radius, samples);
73  		this.radius = radius;
74  		this.samples = samples;
75  		this.threshold = threshold;
76  	}
77  	
78  	/**
79  	 * Calculate the LBP for every pixel in the image. The returned
80  	 * array of LBP codes hase the same dimensions as the image. 
81  	 * 
82  	 * Samples taken from outside the image bounds are assumed to have 
83  	 * the value 0.
84  	 * 
85  	 * @param image the image
86  	 * @param radius the radius of the sampling circle
87  	 * @param samples the number of samples around the circle
88  	 * @param threshold the threshold
89  	 * @return three 2d-arrays of the positive and negative binary LTP codes and the ternary code for every pixel
90  	 */
91  	public static int[][][] calculateLTP(FImage image, float radius, int samples, float threshold) {
92  		checkParams(radius, samples);
93  		
94  		int [][][] pattern = new int[3][image.height][image.width];
95  		
96  		for (int y=0; y<image.height; y++) {
97  			for (int x=0; x<image.width; x++) {
98  				int [] pn = calculateLTP(image, radius, samples, threshold, x, y);
99  				pattern[0][y][x] = pn[0];
100 				pattern[1][y][x] = pn[1];
101 				pattern[2][y][x] = pn[2];
102 			}
103 		}
104 		
105 		return pattern;
106 	}
107 	
108 	/**
109 	 * Calculate the LTP for a single point. The
110 	 * point must be within the image.
111 	 * 
112 	 * @param image the image
113 	 * @param radius the radius of the sampling circle
114 	 * @param samples the number of samples around the circle
115 	 * @param threshold the threshold
116 	 * @param x the x-coordinate of the point
117 	 * @param y the y-coordinate of the point
118 	 * @return the LTP code (positive and negative binary code and ternary code)
119 	 */
120 	public static int[] calculateLTP(FImage image, float radius, int samples, float threshold, int x, int y) {
121 		float centre = image.pixels[y][x];
122 		int pattern[] = new int[3];
123 		
124 		for (int i=0; i<samples; i++) {
125 			double xx = -radius * Math.sin(2 * Math.PI * i / samples);
126 			double yy = radius * Math.cos(2 * Math.PI * i / samples);
127 			
128 			float pix = image.getPixelInterp(x+xx, y+yy);
129 			
130 			float d = pix - centre;
131 			
132 			if (d >= threshold) {
133 				pattern[0] += Math.pow(2, i);
134 				pattern[2] += Math.pow(3, i);
135 			}
136 			if (d <= threshold) {
137 				pattern[1] += Math.pow(2, i);
138 				pattern[2] += 2 * Math.pow(3, i);
139 			}
140 		}
141 		
142 		return pattern;
143 	}
144 
145 	/**
146 	 * Calculate the LTP for a single point. The
147 	 * point must be within the image.
148 	 * 
149 	 * @param image the image
150 	 * @param radius the radius of the sampling circle
151 	 * @param threshold the threshold
152 	 * @param samples the number of samples around the circle
153 	 * @param point the point
154 	 * @return the LTP code (positive and negative binary code and ternary code)
155 	 */
156 	public static int [] calculateLTP(FImage image, float radius, int samples, float threshold, Pixel point) {
157 		return calculateLTP(image, radius, samples, threshold, point.x, point.y);
158 	}
159 
160 	private static void checkParams(float radius, int samples) {
161 		if (radius <= 0) {
162 			throw new IllegalArgumentException("radius must be greater than 0");
163 		}
164 		if (samples <= 1 || samples > 31) {
165 			throw new IllegalArgumentException("samples cannot be less than one or more than 31");
166 		}
167 	}
168 
169 	/* (non-Javadoc)
170 	 * @see org.openimaj.image.analyser.ImageAnalyser#analyseImage(org.openimaj.image.Image)
171 	 */
172 	@Override
173 	public void analyseImage(FImage image) {
174 		int [][][] patterns = calculateLTP(image, radius, samples, threshold);
175 		
176 		positiveBinaryPattern = patterns[0];
177 		negativeBinaryPattern = patterns[1];
178 		ternaryPattern = patterns[2];
179 	}
180 	
181 	/**
182 	 * Get the positive pattern created during the last call to
183 	 * {@link #analyseImage(FImage)}.
184 	 * 
185 	 * @return the pattern
186 	 */
187 	public int[][] getPositivePattern() {
188 		return positiveBinaryPattern;
189 	}
190 	
191 	/**
192 	 * Get the negative pattern created during the last call to
193 	 * {@link #analyseImage(FImage)}.
194 	 * 
195 	 * @return the pattern
196 	 */
197 	public int[][] getNegativePattern() {
198 		return negativeBinaryPattern;
199 	}
200 	
201 	/**
202 	 * Get the ternary pattern created during the last call to
203 	 * {@link #analyseImage(FImage)}.
204 	 * 
205 	 * @return the pattern
206 	 */
207 	public int[][] getTernaryPattern() {
208 		return ternaryPattern;
209 	}
210 }