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.gradient;
31  
32  import org.openimaj.citation.annotation.Reference;
33  import org.openimaj.citation.annotation.ReferenceType;
34  import org.openimaj.feature.DoubleFV;
35  import org.openimaj.feature.FeatureVectorProvider;
36  import org.openimaj.image.FImage;
37  import org.openimaj.image.analyser.ImageAnalyser;
38  import org.openimaj.image.analysis.algorithm.histogram.BinnedWindowedExtractor;
39  import org.openimaj.image.analysis.algorithm.histogram.GradientOrientationHistogramExtractor;
40  import org.openimaj.image.analysis.algorithm.histogram.InterpolatedBinnedWindowedExtractor;
41  import org.openimaj.image.analysis.algorithm.histogram.binning.QuadtreeStrategy;
42  import org.openimaj.image.pixel.sampling.QuadtreeSampler;
43  import org.openimaj.image.processing.convolution.FImageGradients;
44  import org.openimaj.image.processing.convolution.FImageGradients.Mode;
45  import org.openimaj.image.processing.edges.CannyEdgeDetector;
46  import org.openimaj.image.processor.ImageProcessor;
47  import org.openimaj.math.geometry.shape.Rectangle;
48  import org.openimaj.math.statistics.distribution.Histogram;
49  
50  /**
51   * This class is an implementation of an extractor for the PHOG (Pyramid
52   * Histograms of Orientation Gradients) feature described by Bosch et al. The
53   * PHOG feature is computed by creating a quadtree of orientation histograms
54   * over the entire image and appending the histograms for each cell of the
55   * quadtree into a single vector which is then l1 normalised (sum to unity).
56   * <p>
57   * In the original description, only orientations at edge pixels were counted;
58   * that restriction is optional in this implementation. If only edge pixels are
59   * used, then the feature describes the distribution of <b>shape</b> in the
60   * image. Conversely, if all pixels are used, the feature essentially describes
61   * the texture of the image.
62   * <p>
63   * As this class will typically be used to only construct a single feature from
64   * an image, it is built around a {@link BinnedWindowedExtractor} (or
65   * {@link InterpolatedBinnedWindowedExtractor} if interpolation is used). This
66   * will be much more efficient than a
67   * {@link GradientOrientationHistogramExtractor} in the single window case. If
68   * you do need to extract many PHOG-like features different rectangles of the
69   * same image, use a {@link GradientOrientationHistogramExtractor} coupled with
70   * a {@link QuadtreeStrategy} to achieve the desired effect.
71   *
72   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
73   *
74   */
75  @Reference(
76  		type = ReferenceType.Inproceedings,
77  		author = { "Bosch, Anna", "Zisserman, Andrew", "Munoz, Xavier" },
78  		title = "Representing shape with a spatial pyramid kernel",
79  		year = "2007",
80  		booktitle = "Proceedings of the 6th ACM international conference on Image and video retrieval",
81  		pages = { "401", "", "408" },
82  		url = "http://doi.acm.org/10.1145/1282280.1282340",
83  		publisher = "ACM",
84  		series = "CIVR '07",
85  		customData = {
86  				"isbn", "978-1-59593-733-9",
87  				"location", "Amsterdam, The Netherlands",
88  				"numpages", "8",
89  				"doi", "10.1145/1282280.1282340",
90  				"acmid", "1282340",
91  				"address", "New York, NY, USA",
92  				"keywords", "object and video retrieval, shape features, spatial pyramid kernel"
93  		})
94  public class PHOG implements ImageAnalyser<FImage>, FeatureVectorProvider<DoubleFV> {
95  	private int nlevels = 3;
96  	private ImageProcessor<FImage> edgeDetector;
97  	private Mode orientationMode;
98  
99  	private BinnedWindowedExtractor histExtractor;
100 	private Rectangle lastBounds;
101 	private FImage magnitudes;
102 
103 	/**
104 	 * Construct with the values used in the paper: 4 levels (corresponds to l=3
105 	 * in the paper), 40 orientation bins (interpolated), signed gradients
106 	 * (called "shape360" in the original paper) and Canny edge detection.
107 	 */
108 	public PHOG() {
109 		this(4, 40, FImageGradients.Mode.Signed);
110 	}
111 
112 	/**
113 	 * Construct with the given values, using Canny edge detection and gradient
114 	 * histogram interpolation.
115 	 *
116 	 * @param nlevels
117 	 *            number of pyramid levels (note this includes l0, so you might
118 	 *            need 1 more)
119 	 * @param nbins
120 	 *            number of bins
121 	 * @param orientationMode
122 	 *            the orientation mode
123 	 */
124 	public PHOG(int nlevels, int nbins, FImageGradients.Mode orientationMode)
125 	{
126 		this(nlevels, nbins, true, orientationMode, new CannyEdgeDetector());
127 	}
128 
129 	/**
130 	 * Construct with the given parameters. The <code>edgeDetector</code>
131 	 * parameter can be <code>null</code> if you don't want to filter out
132 	 * non-edge pixels from the histograms.
133 	 *
134 	 * @param nlevels
135 	 *            number of pyramid levels (note this includes l0, so you might
136 	 *            need 1 more)
137 	 * @param nbins
138 	 *            number of bins
139 	 * @param histogramInterpolation
140 	 *            should the gradient orientations be interpolated?
141 	 * @param orientationMode
142 	 *            the orientation mode
143 	 * @param edgeDetector
144 	 *            the edge detector to use (may be <code>null</code> for
145 	 *            gradient features)
146 	 */
147 	public PHOG(int nlevels, int nbins, boolean histogramInterpolation, FImageGradients.Mode orientationMode,
148 			ImageProcessor<FImage> edgeDetector)
149 	{
150 		this.nlevels = nlevels;
151 		this.edgeDetector = edgeDetector;
152 		this.orientationMode = orientationMode;
153 
154 		if (histogramInterpolation)
155 			histExtractor = new InterpolatedBinnedWindowedExtractor(nbins, true);
156 		else
157 			histExtractor = new BinnedWindowedExtractor(nbins);
158 
159 		histExtractor.setMax(orientationMode.maxAngle());
160 		histExtractor.setMin(orientationMode.minAngle());
161 	}
162 
163 	@Override
164 	public void analyseImage(FImage image) {
165 		lastBounds = image.getBounds();
166 
167 		final FImageGradients gradMag = FImageGradients.getGradientMagnitudesAndOrientations(image, orientationMode);
168 		this.magnitudes = gradMag.magnitudes;
169 
170 		histExtractor.analyseImage(gradMag.orientations);
171 
172 		if (edgeDetector != null) {
173 			magnitudes.multiplyInplace(image.process(edgeDetector));
174 		}
175 	}
176 
177 	/**
178 	 * Extract the PHOG feature for the specified region of the image last
179 	 * analysed with {@link #analyseImage(FImage)}.
180 	 *
181 	 * @param rect
182 	 *            the region
183 	 * @return the PHOG feature
184 	 */
185 	public Histogram getFeatureVector(Rectangle rect) {
186 		final QuadtreeSampler sampler = new QuadtreeSampler(rect, nlevels + 1);
187 		Histogram hist = new Histogram(0);
188 
189 		for (final Rectangle r : sampler) {
190 			final Histogram h = histExtractor.computeHistogram(r, magnitudes);
191 			hist = hist.combine(h);
192 		}
193 
194 		hist.normaliseL1();
195 
196 		return hist;
197 	}
198 
199 	/**
200 	 * Extract the PHOG feature for the whole of the image last analysed with
201 	 * {@link #analyseImage(FImage)}.
202 	 *
203 	 * @return the PHOG feature
204 	 *
205 	 * @see org.openimaj.feature.FeatureVectorProvider#getFeatureVector()
206 	 */
207 	@Override
208 	public Histogram getFeatureVector() {
209 		return getFeatureVector(lastBounds);
210 	}
211 }