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.docs.tutorial.fund.ml.class101; 031 032import java.io.IOException; 033import java.util.ArrayList; 034import java.util.List; 035import java.util.Map; 036 037import org.openimaj.data.DataSource; 038import org.openimaj.data.dataset.GroupedDataset; 039import org.openimaj.data.dataset.ListDataset; 040import org.openimaj.data.dataset.VFSListDataset; 041import org.openimaj.experiment.dataset.sampling.GroupSampler; 042import org.openimaj.experiment.dataset.sampling.GroupedUniformRandomisedSampler; 043import org.openimaj.experiment.dataset.split.GroupedRandomSplitter; 044import org.openimaj.experiment.evaluation.classification.ClassificationEvaluator; 045import org.openimaj.experiment.evaluation.classification.ClassificationResult; 046import org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMAnalyser; 047import org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMResult; 048import org.openimaj.feature.DoubleFV; 049import org.openimaj.feature.FeatureExtractor; 050import org.openimaj.feature.SparseIntFV; 051import org.openimaj.feature.local.data.LocalFeatureListDataSource; 052import org.openimaj.feature.local.list.LocalFeatureList; 053import org.openimaj.image.FImage; 054import org.openimaj.image.ImageUtilities; 055import org.openimaj.image.annotation.evaluation.datasets.Caltech101; 056import org.openimaj.image.annotation.evaluation.datasets.Caltech101.Record; 057import org.openimaj.image.feature.dense.gradient.dsift.ByteDSIFTKeypoint; 058import org.openimaj.image.feature.dense.gradient.dsift.DenseSIFT; 059import org.openimaj.image.feature.dense.gradient.dsift.PyramidDenseSIFT; 060import org.openimaj.image.feature.local.aggregate.BagOfVisualWords; 061import org.openimaj.image.feature.local.aggregate.BlockSpatialAggregator; 062import org.openimaj.ml.annotation.linear.LiblinearAnnotator; 063import org.openimaj.ml.annotation.linear.LiblinearAnnotator.Mode; 064import org.openimaj.ml.clustering.ByteCentroidsResult; 065import org.openimaj.ml.clustering.assignment.HardAssigner; 066import org.openimaj.ml.clustering.kmeans.ByteKMeans; 067import org.openimaj.util.pair.IntFloatPair; 068 069import de.bwaldvogel.liblinear.SolverType; 070 071/** 072 * OpenIMAJ Hello world! 073 * 074 */ 075public class App { 076 /** 077 * Main method 078 * 079 * @param args 080 * @throws IOException 081 */ 082 public static void main(String[] args) throws IOException { 083 System.out.println("Load dataset and take a sample"); 084 final GroupedDataset<String, VFSListDataset<Record<FImage>>, Record<FImage>> allData = Caltech101 085 .getData(ImageUtilities.FIMAGE_READER); 086 final GroupedDataset<String, ListDataset<Record<FImage>>, Record<FImage>> data = GroupSampler.sample(allData, 5, 087 false); 088 089 System.out.println("Construct the base feature extractor"); 090 final DenseSIFT dsift = new DenseSIFT(5, 7); 091 final PyramidDenseSIFT<FImage> pdsift = new PyramidDenseSIFT<FImage>(dsift, 6f, 7); 092 093 System.out.println("Create training and testing data"); 094 final GroupedRandomSplitter<String, Record<FImage>> splits = new GroupedRandomSplitter<String, Record<FImage>>( 095 data, 15, 0, 15); 096 097 System.out.println("Learn a vocabulary"); 098 final HardAssigner<byte[], float[], IntFloatPair> assigner = trainQuantiser(GroupedUniformRandomisedSampler 099 .sample(splits.getTrainingDataset(), 30), pdsift); 100 101 System.out.println("Define feature extractor"); 102 // final HomogeneousKernelMap map = new 103 // HomogeneousKernelMap(KernelType.Chi2, WindowType.Rectangular); 104 // final FeatureExtractor<DoubleFV, Record<FImage>> extractor = map 105 // .createWrappedExtractor(new PHOWExtractor(pdsift, assigner)); 106 final FeatureExtractor<DoubleFV, Record<FImage>> extractor = new SpPHOWExtractorImplementation(pdsift, assigner); 107 108 System.out.println("Construct and train classifier"); 109 final LiblinearAnnotator<Record<FImage>, String> ann = new LiblinearAnnotator<Record<FImage>, String>( 110 extractor, Mode.MULTICLASS, SolverType.L2R_L2LOSS_SVC, 1.0, 0.00001); 111 ann.train(splits.getTrainingDataset()); 112 113 System.out.println("Evaluate classifier"); 114 final ClassificationEvaluator<CMResult<String>, String, Record<FImage>> eval = new ClassificationEvaluator<CMResult<String>, String, Record<FImage>>( 115 ann, splits.getTestDataset(), new CMAnalyser<Record<FImage>, String>(CMAnalyser.Strategy.SINGLE)); 116 final Map<Record<FImage>, ClassificationResult<String>> guesses = eval.evaluate(); 117 final CMResult<String> result = eval.analyse(guesses); 118 119 System.out.println(result.getDetailReport()); 120 } 121 122 private static final class SpPHOWExtractorImplementation implements FeatureExtractor<DoubleFV, Record<FImage>> { 123 PyramidDenseSIFT<FImage> pdsift; 124 HardAssigner<byte[], float[], IntFloatPair> assigner; 125 126 public SpPHOWExtractorImplementation(PyramidDenseSIFT<FImage> pdsift, 127 HardAssigner<byte[], float[], IntFloatPair> assigner) 128 { 129 this.pdsift = pdsift; 130 this.assigner = assigner; 131 } 132 133 @Override 134 public DoubleFV extractFeature(Record<FImage> object) { 135 final FImage image = object.getImage(); 136 pdsift.analyseImage(image); 137 138 final BagOfVisualWords<byte[]> bovw = new BagOfVisualWords<byte[]>(assigner); 139 140 final BlockSpatialAggregator<byte[], SparseIntFV> spatial = new BlockSpatialAggregator<byte[], SparseIntFV>( 141 bovw, 2, 2); 142 143 // final PyramidSpatialAggregator<byte[], SparseIntFV> spatial = 144 // new PyramidSpatialAggregator<byte[], SparseIntFV>(bovw, 2, 4); 145 146 return spatial.aggregate(pdsift.getByteKeypoints(0.015f), image.getBounds()).normaliseFV(); 147 } 148 } 149 150 private static HardAssigner<byte[], float[], IntFloatPair> trainQuantiser( 151 GroupedDataset<String, ListDataset<Record<FImage>>, Record<FImage>> sample, PyramidDenseSIFT<FImage> pdsift) 152 { 153 List<LocalFeatureList<ByteDSIFTKeypoint>> allkeys = new ArrayList<LocalFeatureList<ByteDSIFTKeypoint>>(); 154 155 for (final Record<FImage> rec : sample) { 156 final FImage img = rec.getImage(); 157 158 pdsift.analyseImage(img); 159 allkeys.add(pdsift.getByteKeypoints(0.005f)); 160 } 161 162 if (allkeys.size() > 10000) 163 allkeys = allkeys.subList(0, 10000); 164 165 final ByteKMeans km = ByteKMeans.createKDTreeEnsemble(300); 166 final DataSource<byte[]> datasource = new LocalFeatureListDataSource<ByteDSIFTKeypoint, byte[]>(allkeys); 167 final ByteCentroidsResult result = km.cluster(datasource); 168 169 return result.defaultHardAssigner(); 170 } 171}