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 org.openimaj.feature.DoubleFV;
33  import org.openimaj.feature.FeatureVectorProvider;
34  import org.openimaj.image.FImage;
35  import org.openimaj.image.MBFImage;
36  import org.openimaj.image.analyser.ImageAnalyser;
37  import org.openimaj.image.colour.Transforms;
38  import org.openimaj.image.mask.AbstractMaskedObject;
39  
40  /**
41   * A two-valued summary representing mean hue (in radians) and variance of hue
42   * respectively. Additionally, can produce a classification for black & white
43   * versus colour versus sepia images based on hand-coded (and not well tested)
44   * parameters.
45   * 
46   * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
47   * 
48   */
49  public class HueStats extends AbstractMaskedObject<FImage>
50  		implements
51  			ImageAnalyser<MBFImage>,
52  			FeatureVectorProvider<DoubleFV>
53  {
54  	double mean_x = 0;
55  	double m2_x = 0;
56  	double mean_y = 0;
57  	double m2_y = 0;
58  	int n = 0;
59  
60  	/**
61  	 * Construct with no mask set
62  	 */
63  	public HueStats() {
64  		super();
65  	}
66  
67  	/**
68  	 * Construct with a mask.
69  	 * 
70  	 * @param mask
71  	 *            the mask.
72  	 */
73  	public HueStats(FImage mask) {
74  		super(mask);
75  	}
76  
77  	@Override
78  	public void analyseImage(MBFImage image) {
79  		// reset vars in case we're reused
80  		mean_x = 0;
81  		m2_x = 0;
82  		mean_y = 0;
83  		m2_y = 0;
84  		n = 0;
85  
86  		final FImage hue = Transforms.calculateHue(image);
87  
88  		for (int j = 0; j < hue.height; j++) {
89  			for (int i = 0; i < hue.width; i++) {
90  				if (mask != null && mask.pixels[j][i] == 0)
91  					continue;
92  
93  				final double angle = hue.pixels[j][i];
94  
95  				final double x = Math.cos(2 * Math.PI * angle);
96  				final double y = Math.sin(2 * Math.PI * angle);
97  
98  				n++;
99  				final double delta_x = x - mean_x;
100 				final double delta_y = y - mean_y;
101 				mean_x += delta_x / n;
102 				mean_y += delta_y / n;
103 
104 				m2_x += delta_x * (x - mean_x);
105 				m2_y += delta_y * (y - mean_y);
106 			}
107 		}
108 	}
109 
110 	/**
111 	 * Get the mean hue value.
112 	 * 
113 	 * @return the mean hue value over all pixels.
114 	 */
115 	public double getMeanHue() {
116 		return Math.atan2(mean_y, mean_x);
117 	}
118 
119 	/**
120 	 * Get the variance in hue value.
121 	 * 
122 	 * @return the variance of hue over all pixels.
123 	 */
124 	public double getHueVariance() {
125 		final double var_x = m2_x / n;
126 		final double var_y = m2_y / n;
127 
128 		return var_y * var_x;
129 	}
130 
131 	/**
132 	 * Tonal attributes for images based on the mean hue and variance.
133 	 * 
134 	 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
135 	 * 
136 	 */
137 	public enum ToneAttr {
138 		/**
139 		 * Sepia toned image.
140 		 */
141 		SEPIA,
142 		/**
143 		 * Black and white image.
144 		 */
145 		BLACK_AND_WHITE,
146 		/**
147 		 * Colour image
148 		 */
149 		COLOR;
150 
151 		/**
152 		 * Estimate the tone from the given mean and variance of the hue. This
153 		 * is hand-crafted and not well tested. A variance bigger than 5e-4 is
154 		 * taken to imply a colour image. If the variance is less than 5e-4 and
155 		 * the mean hue is between -0.1 and 0.1 radians, then it is assumed the
156 		 * image is back and white. If the variance is less than 5e-4 and the
157 		 * mean hue is between -0.6 and 0.8 radians, then it is assumed the
158 		 * image is sepia toned.
159 		 * 
160 		 * @param mean
161 		 *            the mean hue
162 		 * @param var
163 		 *            the variance in hue
164 		 * @return the estimated tone
165 		 */
166 		public static ToneAttr getAttr(double mean, double var) {
167 			if (var < 5e-4) {
168 				if (mean > -0.1 && mean < 0.1)
169 					return BLACK_AND_WHITE;
170 				if (mean > 0.6 && mean < 0.8)
171 					return SEPIA;
172 			}
173 			return COLOR;
174 		}
175 	}
176 
177 	/**
178 	 * Estimate the tone of the image.
179 	 * 
180 	 * @see ToneAttr#getAttr(double, double)
181 	 * 
182 	 * @return the estimated tone
183 	 */
184 	public ToneAttr getTone() {
185 		return ToneAttr.getAttr(getMeanHue(), getHueVariance());
186 	}
187 
188 	@Override
189 	public DoubleFV getFeatureVector() {
190 		return new DoubleFV(new double[] { getMeanHue(), getHueVariance() });
191 	}
192 }