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.saliency; 031 032import org.openimaj.citation.annotation.Reference; 033import org.openimaj.citation.annotation.ReferenceType; 034import org.openimaj.image.FImage; 035import org.openimaj.image.analysis.algorithm.HorizontalProjection; 036import org.openimaj.image.analysis.algorithm.VerticalProjection; 037import org.openimaj.math.geometry.shape.Rectangle; 038 039/** 040 * Extract the subject region of an image based on the 041 * part that is least blurred (most in-focus). 042 * <p> 043 * Algorithm based on: 044 * Yiwen Luo and Xiaoou Tang. 2008. 045 * Photo and Video Quality Evaluation: Focusing on the Subject. 046 * In Proceedings of the 10th European Conference on Computer Vision: 047 * Part III (ECCV '08), David Forsyth, Philip Torr, and Andrew Zisserman (Eds.). 048 * Springer-Verlag, Berlin, Heidelberg, 386-399. DOI=10.1007/978-3-540-88690-7_29 049 * http://dx.doi.org/10.1007/978-3-540-88690-7_29 050 * <p> 051 * Note that this is not scale invariant - you will get different results with 052 * different sized images... 053 * 054 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 055 */ 056@Reference( 057 type = ReferenceType.Inproceedings, 058 author = { "Luo, Yiwen", "Tang, Xiaoou" }, 059 title = "Photo and Video Quality Evaluation: Focusing on the Subject", 060 year = "2008", 061 booktitle = "Proceedings of the 10th European Conference on Computer Vision: Part III", 062 pages = { "386", "", "399" }, 063 url = "http://dx.doi.org/10.1007/978-3-540-88690-7_29", 064 publisher = "Springer-Verlag", 065 series = "ECCV '08", 066 customData = { 067 "isbn", "978-3-540-88689-1", 068 "location", "Marseille, France", 069 "numpages", "14", 070 "doi", "10.1007/978-3-540-88690-7_29", 071 "acmid", "1478204", 072 "address", "Berlin, Heidelberg" 073 } 074 ) 075public class LuoTangSubjectRegion implements SaliencyMapGenerator<FImage> { 076 DepthOfFieldEstimator dofEstimator; 077 078 Rectangle roi; 079 private FImage dofMap; 080 private float alpha = 0.9f; 081 082 /** 083 * Construct with default values for the {@link DepthOfFieldEstimator} 084 * and an alpha parameter of 0.9. 085 */ 086 public LuoTangSubjectRegion() { 087 dofEstimator = new DepthOfFieldEstimator(); 088 } 089 090 /** 091 * Construct with the given parameters. 092 * @param alpha the alpha value. 093 * @param maxKernelSize Maximum kernel size for the {@link DepthOfFieldEstimator}. 094 * @param kernelSizeStep Kernel step size for the {@link DepthOfFieldEstimator}. 095 * @param nbins Number of bins for the {@link DepthOfFieldEstimator}. 096 * @param windowSize window size for the {@link DepthOfFieldEstimator}. 097 */ 098 public LuoTangSubjectRegion(float alpha, int maxKernelSize, int kernelSizeStep, int nbins, int windowSize) { 099 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}