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.global;
31  
32  import gnu.trove.map.hash.TObjectFloatHashMap;
33  import gnu.trove.procedure.TObjectFloatProcedure;
34  
35  import org.openimaj.citation.annotation.Reference;
36  import org.openimaj.citation.annotation.ReferenceType;
37  import org.openimaj.citation.annotation.References;
38  import org.openimaj.feature.DoubleFV;
39  import org.openimaj.feature.FeatureVectorProvider;
40  import org.openimaj.image.FImage;
41  import org.openimaj.image.MBFImage;
42  import org.openimaj.image.analyser.ImageAnalyser;
43  import org.openimaj.image.pixel.ConnectedComponent;
44  import org.openimaj.image.pixel.statistics.MaskingHistogramModel;
45  import org.openimaj.image.processor.connectedcomponent.render.BoundingBoxRenderer;
46  import org.openimaj.image.saliency.AchantaSaliency;
47  import org.openimaj.image.saliency.YehSaliency;
48  import org.openimaj.image.segmentation.FelzenszwalbHuttenlocherSegmenter;
49  import org.openimaj.math.statistics.distribution.MultidimensionalHistogram;
50  import org.openimaj.util.array.ArrayUtils;
51  
52  /**
53   * Estimate the simplicity of an image by looking at the colour distribution of
54   * the background.
55   * <p>
56   * Algorithm based on that proposed by Yiwen Luo and Xiaoou Tang, but modified
57   * to use the foreground detection approach suggested in Che-Hua Yeh et al.
58   *
59   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
60   */
61  @References(references = {
62  		@Reference(
63  				type = ReferenceType.Inproceedings,
64  				author = { "Luo, Yiwen", "Tang, Xiaoou" },
65  				title = "Photo and Video Quality Evaluation: Focusing on the Subject",
66  				year = "2008",
67  				booktitle = "Proceedings of the 10th European Conference on Computer Vision: Part III",
68  				pages = { "386", "399" },
69  				url = "http://dx.doi.org/10.1007/978-3-540-88690-7_29",
70  				publisher = "Springer-Verlag",
71  				series = "ECCV '08",
72  				customData = { "isbn", "978-3-540-88689-1", "location", "Marseille, France", "numpages", "14", "doi",
73  						"10.1007/978-3-540-88690-7_29", "acmid", "1478204", "address", "Berlin, Heidelberg" }),
74  						@Reference(
75  								type = ReferenceType.Inproceedings,
76  								author = { "Che-Hua Yeh", "Yuan-Chen Ho", "Brian A. Barsky", "Ming Ouhyoung" },
77  								title = "Personalized Photograph Ranking and Selection System",
78  								year = "2010",
79  								booktitle = "Proceedings of ACM Multimedia",
80  								pages = { "211", "220" },
81  								month = "October",
82  								customData = { "location", "Florence, Italy" }) })
83  public class ModifiedLuoSimplicity implements ImageAnalyser<MBFImage>, FeatureVectorProvider<DoubleFV> {
84  	protected YehSaliency extractor;
85  	protected float alpha = 0.67f;
86  
87  	protected int binsPerBand = 16;
88  	protected float gamma = 0.01f;
89  	protected boolean boxMode = true;
90  	protected double simplicity;
91  
92  	/**
93  	 * Construct with the default values
94  	 */
95  	public ModifiedLuoSimplicity() {
96  		extractor = new YehSaliency();
97  	}
98  
99  	/**
100 	 * Construct with the given values
101 	 *
102 	 * @param binsPerBand
103 	 *            the number of histogram bins per colour band
104 	 * @param gamma
105 	 *            the gamma value for determining the threshold
106 	 * @param boxMode
107 	 *            whether to extract rectangular boxes for the foreground
108 	 *            regions (true) or to just use the pixels (false)
109 	 * @param alpha
110 	 *            the alpha value for determining the foreground/background
111 	 *            threshold
112 	 * @param saliencySigma
113 	 *            smoothing for the {@link AchantaSaliency} class
114 	 * @param segmenterSigma
115 	 *            smoothing for {@link FelzenszwalbHuttenlocherSegmenter}.
116 	 * @param k
117 	 *            k value for {@link FelzenszwalbHuttenlocherSegmenter}.
118 	 * @param minSize
119 	 *            minimum region size for
120 	 *            {@link FelzenszwalbHuttenlocherSegmenter}.
121 	 */
122 	public ModifiedLuoSimplicity(int binsPerBand, float gamma, boolean boxMode, float alpha, float saliencySigma,
123 			float segmenterSigma, float k, int minSize)
124 	{
125 		extractor = new YehSaliency(saliencySigma, segmenterSigma, k, minSize);
126 		this.binsPerBand = binsPerBand;
127 		this.gamma = gamma;
128 		this.boxMode = boxMode;
129 		this.alpha = alpha;
130 	}
131 
132 	/*
133 	 * (non-Javadoc)
134 	 *
135 	 * @see
136 	 * org.openimaj.image.analyser.ImageAnalyser#analyseImage(org.openimaj.image
137 	 * .Image)
138 	 */
139 	@Override
140 	public void analyseImage(MBFImage image) {
141 		image.analyseWith(extractor);
142 
143 		FImage mask;
144 		if (boxMode) {
145 			final TObjectFloatHashMap<ConnectedComponent> componentMap = extractor.getSaliencyComponents();
146 
147 			final float max = ArrayUtils.maxValue(componentMap.values());
148 
149 			mask = new FImage(image.getWidth(), image.getHeight());
150 			final float thresh = max * alpha;
151 			final BoundingBoxRenderer<Float> renderer = new BoundingBoxRenderer<Float>(mask, 1F, true);
152 
153 			componentMap.forEachEntry(new TObjectFloatProcedure<ConnectedComponent>() {
154 				@Override
155 				public boolean execute(ConnectedComponent cc, float sal) {
156 					if (sal >= thresh) { // note that this is reversed from the
157 						// paper, which doesn't seem to make
158 						// sense.
159 						renderer.process(cc);
160 					}
161 
162 					return true;
163 				}
164 			});
165 		} else {
166 			mask = extractor.getSaliencyMap();
167 			final float maskthresh = mask.max() * alpha;
168 			mask = mask.threshold(maskthresh);
169 		}
170 
171 		mask = mask.inverse();
172 
173 		final MaskingHistogramModel hm = new MaskingHistogramModel(mask, binsPerBand, binsPerBand, binsPerBand);
174 		hm.estimateModel(image);
175 
176 		final MultidimensionalHistogram fv = hm.getFeatureVector();
177 		final double thresh = gamma * fv.max();
178 		int count = 0;
179 		for (final double f : fv.values) {
180 			if (f >= thresh)
181 				count++;
182 		}
183 
184 		simplicity = (double) count / (double) fv.values.length;
185 	}
186 
187 	@Override
188 	public DoubleFV getFeatureVector() {
189 		return new DoubleFV(new double[] { simplicity });
190 	}
191 }