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 java.util.List; 033 034import org.openimaj.citation.annotation.Reference; 035import org.openimaj.citation.annotation.ReferenceType; 036import org.openimaj.feature.DoubleFV; 037import org.openimaj.feature.FeatureVectorProvider; 038import org.openimaj.image.MBFImage; 039import org.openimaj.image.analyser.ImageAnalyser; 040import org.openimaj.image.analysis.colour.CIEDE2000; 041import org.openimaj.image.colour.ColourSpace; 042import org.openimaj.image.pixel.ConnectedComponent; 043import org.openimaj.image.pixel.Pixel; 044import org.openimaj.image.pixel.PixelSet; 045import org.openimaj.image.segmentation.FelzenszwalbHuttenlocherSegmenter; 046 047/** 048 * Implementation of a color contrast feature. 049 * <p> 050 * The feature is calculated by performing a weighted average of the average 051 * colour difference of all the segments in the image. 052 * 053 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 054 */ 055@Reference( 056 type = ReferenceType.Inproceedings, 057 author = { "Che-Hua Yeh", "Yuan-Chen Ho", "Brian A. Barsky", "Ming Ouhyoung" }, 058 title = "Personalized Photograph Ranking and Selection System", 059 year = "2010", 060 booktitle = "Proceedings of ACM Multimedia", 061 pages = { "211", "220" }, 062 month = "October", 063 customData = { "location", "Florence, Italy" }) 064public class ColourContrast implements ImageAnalyser<MBFImage>, FeatureVectorProvider<DoubleFV> { 065 FelzenszwalbHuttenlocherSegmenter<MBFImage> segmenter; 066 double contrast; 067 068 /** 069 * Construct the {@link ColourContrast} feature extractor using the default 070 * settings for the {@link FelzenszwalbHuttenlocherSegmenter}. 071 */ 072 public ColourContrast() { 073 segmenter = new FelzenszwalbHuttenlocherSegmenter<MBFImage>(); 074 } 075 076 /** 077 * Construct the {@link ColourContrast} feature extractor with the given 078 * parameters for the underlying {@link FelzenszwalbHuttenlocherSegmenter}. 079 * 080 * @param sigma 081 * amount of blurring 082 * @param k 083 * threshold 084 * @param minSize 085 * minimum allowed component size 086 */ 087 public ColourContrast(float sigma, float k, int minSize) { 088 segmenter = new FelzenszwalbHuttenlocherSegmenter<MBFImage>(sigma, k, minSize); 089 } 090 091 @Override 092 public DoubleFV getFeatureVector() { 093 return new DoubleFV(new double[] { contrast }); 094 } 095 096 /* 097 * (non-Javadoc) 098 * 099 * @see 100 * org.openimaj.image.processor.ImageProcessor#processImage(org.openimaj 101 * .image.Image) 102 */ 103 @Override 104 public void analyseImage(MBFImage image) { 105 final List<ConnectedComponent> ccs = segmenter.segment(image); 106 final MBFImage labImage = ColourSpace.convert(image, ColourSpace.CIE_Lab); 107 final float[][] avgs = new float[ccs.size()][3]; 108 final int w = image.getWidth(); 109 final int h = image.getHeight(); 110 111 // calculate patch average colours 112 for (int i = 0; i < avgs.length; i++) { 113 for (final Pixel p : ccs.get(i).pixels) { 114 final Float[] v = labImage.getPixel(p); 115 116 avgs[i][0] += v[0]; 117 avgs[i][0] += v[1]; 118 avgs[i][0] += v[2]; 119 } 120 final int sz = ccs.get(i).pixels.size(); 121 avgs[i][0] /= sz; 122 avgs[i][1] /= sz; 123 avgs[i][2] /= sz; 124 } 125 126 for (int i = 0; i < avgs.length; i++) { 127 for (int j = i + 1; j < avgs.length; j++) { 128 final PixelSet ci = ccs.get(i); 129 final PixelSet cj = ccs.get(i); 130 final float C = CIEDE2000.calculateDeltaE(avgs[i], avgs[j]); 131 132 contrast += (1 - distance(ci, cj, w, h)) * (C / (ci.calculateArea() * cj.calculateArea())); 133 } 134 } 135 } 136 137 float distance(PixelSet c1, PixelSet c2, int w, int h) { 138 final double[] cen1 = c1.calculateCentroid(); 139 final double[] cen2 = c2.calculateCentroid(); 140 141 final double dx = (cen1[0] - cen2[0]) / w; 142 final double dy = (cen1[1] - cen2[1]) / h; 143 144 return (float) (Math.sqrt(dx * dx + dy * dy) / Math.sqrt(2)); 145 } 146}