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.objectdetection.haar.training; 031 032import java.util.ArrayList; 033import java.util.Arrays; 034import java.util.Collection; 035import java.util.EnumSet; 036import java.util.List; 037 038import org.openimaj.image.objectdetection.haar.HaarFeature; 039 040/** 041 * Definitions of standard haar-like features. 042 * 043 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 044 * 045 */ 046public enum HaarFeatureType { 047 /** 048 * Two component feature: 049 * 050 * <pre> 051 * 0 X 052 * </pre> 053 */ 054 X2 { 055 @Override 056 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 057 // haar_x2 058 if ((x + dx * 2 <= winWidth) && (y + dy <= winHeight)) { 059 return HaarFeature.create(false, 060 x, y, dx * 2, dy, -1, 061 x + dx, y, dx, dy, +2); 062 } 063 return null; 064 } 065 }, 066 /** 067 * Two component feature: 068 * 069 * <pre> 070 * 0 071 * X 072 * </pre> 073 */ 074 Y2 { 075 @Override 076 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 077 // haar_y2 078 if ((x + dx <= winWidth) && (y + dy * 2 <= winHeight)) { 079 return HaarFeature.create(false, 080 x, y, dx, dy * 2, -1, 081 x, y + dy, dx, dy, +2); 082 } 083 return null; 084 } 085 }, 086 /** 087 * Three component feature: 088 * 089 * <pre> 090 * 0 X 0 091 * </pre> 092 */ 093 X3 { 094 @Override 095 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 096 // haar_x3 097 if ((x + dx * 3 <= winWidth) && (y + dy <= winHeight)) { 098 return HaarFeature.create(false, 099 x, y, dx * 3, dy, -1, 100 x + dx, y, dx, dy, +3); 101 } 102 return null; 103 } 104 }, 105 /** 106 * Three component feature: 107 * 108 * <pre> 109 * 0 110 * X 111 * 0 112 * </pre> 113 */ 114 Y3 { 115 @Override 116 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 117 // haar_y3 118 if ((x + dx <= winWidth) && (y + dy * 3 <= winHeight)) { 119 return HaarFeature.create(false, 120 x, y, dx, dy * 3, -1, 121 x, y + dy, dx, dy, +3); 122 } 123 return null; 124 } 125 }, 126 /** 127 * Three component feature: 128 * 129 * <pre> 130 * 0 X X 0 131 * </pre> 132 */ 133 X4 { 134 @Override 135 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 136 // haar_x4 137 if ((x + dx * 4 <= winWidth) && (y + dy <= winHeight)) { 138 return HaarFeature.create(false, 139 x, y, dx * 4, dy, -1, 140 x + dx, y, dx * 2, dy, +2); 141 } 142 return null; 143 } 144 }, 145 /** 146 * Three component feature: 147 * 148 * <pre> 149 * 0 150 * X 151 * X 152 * 0 153 * </pre> 154 */ 155 Y4 { 156 @Override 157 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 158 // haar_y4 159 if ((x + dx <= winWidth) && (y + dy * 4 <= winHeight)) { 160 return HaarFeature.create(false, 161 x, y, dx, dy * 4, -1, 162 x, y + dy, dx, dy * 2, +2); 163 } 164 return null; 165 } 166 }, 167 /** 168 * Four component feature: 169 * 170 * <pre> 171 * X 0 172 * 0 X 173 * </pre> 174 */ 175 X2Y2 { 176 @Override 177 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 178 // x2_y2 179 if ((x + dx * 2 <= winWidth) && (y + dy * 2 <= winHeight)) { 180 return HaarFeature.create(false, 181 x, y, dx * 2, dy * 2, -1, 182 x, y, dx, dy, +2, 183 x + dx, y + dy, dx, dy, +2); 184 } 185 return null; 186 } 187 }, 188 /** 189 * Centre-surround feature: 190 * 191 * <pre> 192 * 0 0 0 193 * 0 X 0 194 * 0 0 0 195 * </pre> 196 */ 197 CS { 198 @Override 199 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 200 if ((x + dx * 3 <= winWidth) && (y + dy * 3 <= winHeight)) { 201 return HaarFeature.create(false, 202 x, y, dx * 3, dy * 3, -1, 203 x + dx, y + dy, dx, dy, +9); 204 } 205 return null; 206 } 207 }, 208 /** 209 * Tilted two component feature: 210 * 211 * <pre> 212 * 0 - -X 213 * </pre> 214 */ 215 TX2 { 216 @Override 217 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 218 // tilted haar_x2 219 if ((x + 2 * dx <= winWidth) && (y + 2 * dx + dy <= winHeight) && (x - dy 220 >= 0)) 221 { 222 return HaarFeature.create(true, 223 x, y, dx * 2, dy, -1, 224 x, y, dx, dy, +2); 225 } 226 return null; 227 } 228 }, 229 /** 230 * Tilted two component feature: 231 * 232 * <pre> 233 * - 0 234 * X - 235 * </pre> 236 */ 237 TY2 { 238 @Override 239 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 240 // tilted haar_y2 241 if ((x + dx <= winWidth) && (y + dx + 2 * dy <= winHeight) && (x - 2 * dy 242 >= 0)) 243 { 244 return HaarFeature.create(true, 245 x, y, dx, 2 * dy, -1, 246 x, y, dx, dy, +2); 247 } 248 return null; 249 } 250 }, 251 /** 252 * Tilted three component feature: 253 * 254 * <pre> 255 * 0 - - 256 * -X - 257 * - -0 258 * </pre> 259 */ 260 TX3 { 261 @Override 262 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 263 // tilted haar_x3 264 if ((x + 3 * dx <= winWidth) && (y + 3 * dx + dy <= winHeight) && (x - dy 265 >= 0)) 266 { 267 return HaarFeature.create(true, 268 x, y, dx * 3, dy, -1, 269 x + dx, y + dx, dx, dy, +3); 270 } 271 return null; 272 } 273 }, 274 /** 275 * Tilted three component feature: 276 * 277 * <pre> 278 * - - 0 279 * - X - 280 * 0 - - 281 * </pre> 282 */ 283 TY3 { 284 @Override 285 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 286 // tilted haar_y3 287 if ((x + dx <= winWidth) && (y + dx + 3 * dy <= winHeight) && (x - 3 * dy 288 >= 0)) 289 { 290 return HaarFeature.create(true, 291 x, y, dx, 3 * dy, -1, 292 x - dy, y + dy, dx, dy, +3); 293 } 294 return null; 295 } 296 }, 297 /** 298 * Tilted three component feature: 299 * 300 * <pre> 301 * 0 - - - 302 * -X - - 303 * - -X - 304 * - - -0 305 * </pre> 306 */ 307 TX4 { 308 @Override 309 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 310 // tilted haar_x4 311 if ((x + 4 * dx <= winWidth) && (y + 4 * dx + dy <= winHeight) && (x - dy 312 >= 0)) 313 { 314 return HaarFeature.create(true, 315 x, y, dx * 4, dy, -1, 316 x + dx, y + dx, dx * 2, dy, +2); 317 } 318 return null; 319 } 320 }, 321 /** 322 * Tilted three component feature: 323 * 324 * <pre> 325 * - - - 0 326 * - - X - 327 * - X - - 328 * 0 - - - 329 * </pre> 330 */ 331 TY4 { 332 @Override 333 public HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight) { 334 // tilted haar_y4 335 if ((x + dx <= winWidth) && (y + dx + 4 * dy <= winHeight) && (x - 4 * dy 336 >= 0)) 337 { 338 return HaarFeature.create(true, 339 x, y, dx, 4 * dy, -1, 340 x - dy, y + dy, dx, 2 * dy, +2); 341 } 342 return null; 343 } 344 }; 345 346 /** 347 * Set of all the features 348 */ 349 public static EnumSet<HaarFeatureType> ALL = EnumSet.allOf(HaarFeatureType.class); 350 351 /** 352 * Set of the basic features (non tilted edges & lines + {@link #X2Y2}) 353 */ 354 public static EnumSet<HaarFeatureType> BASIC = EnumSet.of(X2, Y2, X3, Y3, X2Y2); 355 356 /** 357 * Set of the core features (all but tilted features) 358 */ 359 public static EnumSet<HaarFeatureType> CORE = EnumSet.of(X2, Y2, X3, Y3, X2Y2, X4, Y4, CS); 360 361 /** 362 * Create a feature. 363 * 364 * @param x 365 * x-location 366 * @param y 367 * y-location 368 * @param dx 369 * x-delta 370 * @param dy 371 * y-delta 372 * @param winWidth 373 * window width 374 * @param winHeight 375 * window height 376 * @return the new feature, or null if the parameters are out of range. 377 */ 378 public abstract HaarFeature create(int x, int y, int dx, int dy, int winWidth, int winHeight); 379 380 /** 381 * Generate features of the given types for all possible locations and sizes 382 * in the given window bounds. 383 * 384 * @param winWidth 385 * window width 386 * @param winHeight 387 * window height 388 * @param types 389 * types of feature to generate 390 * @return the generated features 391 */ 392 public static List<HaarFeature> generateFeatures(int winWidth, int winHeight, HaarFeatureType... types) { 393 return generateFeatures(winWidth, winHeight, Arrays.asList(types)); 394 } 395 396 /** 397 * Generate features of the given types for all possible locations and sizes 398 * in the given window bounds. 399 * 400 * @param winWidth 401 * window width 402 * @param winHeight 403 * window height 404 * @param types 405 * types of feature to generate 406 * @return the generated features 407 */ 408 public static List<HaarFeature> generateFeatures(int winWidth, int winHeight, Collection<HaarFeatureType> types) { 409 final List<HaarFeature> features = new ArrayList<HaarFeature>(); 410 411 for (int x = 0; x < winWidth; x++) { 412 for (int y = 0; y < winHeight; y++) { 413 for (int dx = 1; dx <= winWidth; dx++) { 414 for (int dy = 1; dy <= winHeight; dy++) { 415 for (final HaarFeatureType type : types) { 416 final HaarFeature f = type.create(x, y, dx, dy, winWidth, winHeight); 417 418 if (f != null) { 419 features.add(f); 420 } 421 } 422 } 423 } 424 } 425 } 426 427 return features; 428 } 429}