001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image.feature.global; 031 032import org.openimaj.feature.DoubleFV; 033import org.openimaj.feature.FeatureVectorProvider; 034import org.openimaj.image.FImage; 035import org.openimaj.image.MBFImage; 036import org.openimaj.image.analyser.ImageAnalyser; 037import org.openimaj.image.colour.Transforms; 038import org.openimaj.image.mask.AbstractMaskedObject; 039 040/** 041 * A two-valued summary representing mean hue (in radians) and variance of hue 042 * respectively. Additionally, can produce a classification for black & white 043 * versus colour versus sepia images based on hand-coded (and not well tested) 044 * parameters. 045 * 046 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 047 * 048 */ 049public class HueStats extends AbstractMaskedObject<FImage> 050 implements 051 ImageAnalyser<MBFImage>, 052 FeatureVectorProvider<DoubleFV> 053{ 054 double mean_x = 0; 055 double m2_x = 0; 056 double mean_y = 0; 057 double m2_y = 0; 058 int n = 0; 059 060 /** 061 * Construct with no mask set 062 */ 063 public HueStats() { 064 super(); 065 } 066 067 /** 068 * Construct with a mask. 069 * 070 * @param mask 071 * the mask. 072 */ 073 public HueStats(FImage mask) { 074 super(mask); 075 } 076 077 @Override 078 public void analyseImage(MBFImage image) { 079 // reset vars in case we're reused 080 mean_x = 0; 081 m2_x = 0; 082 mean_y = 0; 083 m2_y = 0; 084 n = 0; 085 086 final FImage hue = Transforms.calculateHue(image); 087 088 for (int j = 0; j < hue.height; j++) { 089 for (int i = 0; i < hue.width; i++) { 090 if (mask != null && mask.pixels[j][i] == 0) 091 continue; 092 093 final double angle = hue.pixels[j][i]; 094 095 final double x = Math.cos(2 * Math.PI * angle); 096 final double y = Math.sin(2 * Math.PI * angle); 097 098 n++; 099 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}