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.saliency;
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.analysis.algorithm.HorizontalProjection;
36  import org.openimaj.image.analysis.algorithm.VerticalProjection;
37  import org.openimaj.math.geometry.shape.Rectangle;
38  
39  /**
40   * Extract the subject region of an image based on the
41   * part that is least blurred (most in-focus).
42   * <p>
43   * Algorithm based on:
44   * Yiwen Luo and Xiaoou Tang. 2008. 
45   * Photo and Video Quality Evaluation: Focusing on the Subject. 
46   * In Proceedings of the 10th European Conference on Computer Vision: 
47   * Part III (ECCV '08), David Forsyth, Philip Torr, and Andrew Zisserman (Eds.). 
48   * Springer-Verlag, Berlin, Heidelberg, 386-399. DOI=10.1007/978-3-540-88690-7_29 
49   * http://dx.doi.org/10.1007/978-3-540-88690-7_29
50   * <p>
51   * Note that this is not scale invariant - you will get different results with
52   * different sized images...
53   * 
54   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
55   */
56  @Reference(
57  		type = ReferenceType.Inproceedings,
58  		author = { "Luo, Yiwen", "Tang, Xiaoou" },
59  		title = "Photo and Video Quality Evaluation: Focusing on the Subject",
60  		year = "2008",
61  		booktitle = "Proceedings of the 10th European Conference on Computer Vision: Part III",
62  		pages = { "386", "", "399" },
63  		url = "http://dx.doi.org/10.1007/978-3-540-88690-7_29",
64  		publisher = "Springer-Verlag",
65  		series = "ECCV '08",
66  		customData = { 
67  				"isbn", "978-3-540-88689-1", 
68  				"location", "Marseille, France", 
69  				"numpages", "14", 
70  				"doi", "10.1007/978-3-540-88690-7_29", 
71  				"acmid", "1478204", 
72  				"address", "Berlin, Heidelberg" 
73  		}
74  	)
75  public class LuoTangSubjectRegion implements SaliencyMapGenerator<FImage> {
76  	DepthOfFieldEstimator dofEstimator;
77  	
78  	Rectangle roi;
79  	private FImage dofMap;
80  	private float alpha = 0.9f;
81  	
82  	/**
83  	 * Construct with default values for the {@link DepthOfFieldEstimator} 
84  	 * and an alpha parameter of 0.9.
85  	 */
86  	public LuoTangSubjectRegion() {
87  		dofEstimator = new DepthOfFieldEstimator();
88  	}
89  	
90  	/**
91  	 * Construct with the given parameters.
92  	 * @param alpha the alpha value.
93  	 * @param maxKernelSize Maximum kernel size for the {@link DepthOfFieldEstimator}.
94  	 * @param kernelSizeStep Kernel step size for the {@link DepthOfFieldEstimator}.
95  	 * @param nbins Number of bins for the {@link DepthOfFieldEstimator}.
96  	 * @param windowSize window size for the {@link DepthOfFieldEstimator}.
97  	 */
98  	public LuoTangSubjectRegion(float alpha, int maxKernelSize, int kernelSizeStep, int nbins, int windowSize) {
99  		this.dofEstimator = new DepthOfFieldEstimator(maxKernelSize, kernelSizeStep, nbins, windowSize);
100 		this.alpha = alpha;
101 	}
102 	
103 	/* (non-Javadoc)
104 	 * @see org.openimaj.image.analyser.ImageAnalyser#analyseImage(org.openimaj.image.Image)
105 	 */
106 	@Override
107 	public void analyseImage(FImage image) {
108 		image.analyseWith(dofEstimator);
109 		dofMap = dofEstimator.getSaliencyMap();
110 		
111 		for (int y=0; y<dofMap.height; y++) {
112 			for (int x=0; x<dofMap.width; x++) {
113 				if (dofMap.pixels[y][x] == 0) 
114 					dofMap.pixels[y][x] = 1;
115 				else 
116 					dofMap.pixels[y][x] = 0;
117 			}
118 		}
119 	}
120 	
121 	/**
122 	 * @return the estimated rectangular region of interest
123 	 */
124 	public Rectangle calculateROI() {		
125 		float [] pUx = HorizontalProjection.project(dofMap);
126 		float [] pUy = VerticalProjection.project(dofMap);
127 		
128 		float energy = 0;
129 		for (float f : pUx) energy += f;
130 		float thresh = energy * ((1 - alpha) / 2);
131 		
132 		int x1 = 0;
133 		float tmp = pUx[x1];
134 		while (tmp < thresh) {
135 			x1++;
136 			tmp += pUx[x1];
137 		}
138 		
139 		int y1 = 0;
140 		tmp = pUy[y1];
141 		while (tmp < thresh) {
142 			y1++;
143 			tmp += pUy[y1];
144 		}
145 		
146 		int x2 = pUx.length - 1;
147 		tmp = pUx[x2];
148 		while (tmp < thresh) {
149 			x2--;
150 			tmp += pUx[x2];
151 		}
152 		
153 		int y2 = pUy.length - 1;
154 		tmp = pUy[y2];
155 		while (tmp < thresh) {
156 			y2--;
157 			tmp += pUy[y2];
158 		}
159 		
160 		return new Rectangle(x1, y1, x2-x1, y2-y1);
161 	}
162 
163 	@Override
164 	public FImage getSaliencyMap() {
165 		return dofMap;
166 	}
167 	
168 	/**
169 	 * @return a mask image showing the region of interest.
170 	 */
171 	public FImage getROIMap() {
172 		FImage image = new FImage(dofMap.width, dofMap.height);
173 		image.drawShapeFilled(calculateROI(), 1f);
174 		return image;
175 	}
176 }