diff --git a/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/App.java b/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/App.java index 41e666879dfcb66d805b6bef3d3cf6b5bd212954..e061f9b06d1f389c7a131882c819e1259d4f365b 100644 --- a/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/App.java +++ b/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/App.java @@ -17,11 +17,18 @@ import org.openimaj.feature.FloatFV; import org.openimaj.feature.SparseIntFV; import org.openimaj.feature.local.LocalFeatureImpl; import org.openimaj.feature.local.Location; +import org.openimaj.feature.local.SpatialLocation; import org.openimaj.feature.local.data.LocalFeatureListDataSource; import org.openimaj.feature.local.list.LocalFeatureList; +import org.openimaj.feature.local.list.MemoryLocalFeatureList; import org.openimaj.image.FImage; +import org.openimaj.image.Image; import org.openimaj.image.ImageUtilities; +import org.openimaj.image.analyser.ImageAnalyser; import org.openimaj.image.feature.local.aggregate.BagOfVisualWords; +import org.openimaj.image.pixel.sampling.RectangleSampler; +import org.openimaj.image.processor.SinglebandImageProcessor; +import org.openimaj.math.geometry.shape.Rectangle; import org.openimaj.ml.annotation.linear.LiblinearAnnotator; import org.openimaj.ml.clustering.FloatCentroidsResult; import org.openimaj.ml.clustering.assignment.HardAssigner; @@ -29,6 +36,7 @@ import org.openimaj.ml.clustering.kmeans.FloatKMeans; import org.openimaj.util.pair.IntFloatPair; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -45,7 +53,7 @@ public class App { VFSListDataset<FImage> testingData; try { trainingData = new VFSGroupDataset<FImage>( - "zip:C:/Users/isaac/Documents/GitHub Repos/visioncw3/visioncw3/data/training.zip", ImageUtilities.FIMAGE_READER); + "zip:http://comp3204.ecs.soton.ac.uk/cw/training.zip", ImageUtilities.FIMAGE_READER); testingData = new VFSListDataset<FImage>( "zip:C:/Users/isaac/Documents/GitHub Repos/visioncw3/visioncw3/data/testing.zip", ImageUtilities.FIMAGE_READER); } catch (Exception e) { @@ -62,7 +70,7 @@ public class App { //analyse patches of 8x8 sizes - PatchFeature patch = new PatchFeature(8); + PatchFeature patch = new PatchFeature(8f,4f, 4f); //train quantiser on a sample of the data set @@ -74,11 +82,13 @@ public class App { FeatureExtractor<SparseIntFV, FImage> extractor = new PatchExtractor(patch, assigner); + //train classification LiblinearAnnotator<FImage, String> ann = new LiblinearAnnotator<FImage, String>( extractor, LiblinearAnnotator.Mode.MULTICLASS, SolverType.L2R_L2LOSS_SVC, 1.0, 0.00001); ann.train(splits.getTrainingDataset()); + //evaluation ClassificationEvaluator<CMResult<String>, String, FImage> eval = new ClassificationEvaluator<CMResult<String>, String, FImage>( ann, splits.getTestDataset(), new CMAnalyser<FImage, String>(CMAnalyser.Strategy.SINGLE)); @@ -90,39 +100,75 @@ public class App { } + + /** + * @desc trains the quantiser using a sample of data and densely sampled patches + * @param sample sample of image data + * @param patch patch sampler + * @return trained assigner + */ static HardAssigner<float[], float[], IntFloatPair> trainQuantiser( Dataset<FImage> sample, PatchFeature<FImage> patch) { List<LocalFeatureList<LocalFeatureImpl<Location, FloatFV>>> allkeys = new ArrayList<>(); + for (FImage rec : sample) { FImage img = rec; + //densely sample patches and store patch.analyseImage(img); allkeys.add(patch.getPatchKeypoints()); } + + //take first 1000 samples if (allkeys.size() > 10000) allkeys = allkeys.subList(0, 10000); + + //k-means clustering FloatKMeans km = FloatKMeans.createExact(500); - DataSource<float[]> datasource = new LocalFeatureListDataSource<LocalFeatureImpl<Location, FloatFV>, float[]>(allkeys); + DataSource<float[]> datasource = + new LocalFeatureListDataSource<LocalFeatureImpl<Location, FloatFV>, float[]>(allkeys); FloatCentroidsResult result = km.cluster(datasource); + return result.defaultHardAssigner(); } } + + + + +/** + * @desc feature extractor to sample patches as visual words + */ class PatchExtractor implements FeatureExtractor<SparseIntFV, FImage> { PatchFeature<FImage> patch; HardAssigner<float[], float[], IntFloatPair> assigner; + + + /** + * @desc construct an extractor using a patch sampler and assigner + * @param patch a dense patch sampler + * @param assigner the trained quantiser + */ public PatchExtractor(PatchFeature<FImage> patch, HardAssigner<float[], float[], IntFloatPair> assigner) { this.patch = patch; this.assigner = assigner; } + + + /** + * @desc extract visual words from image + * @param object FImage to extract from + * @return extracted visual words as a SpareIntFV + */ public SparseIntFV extractFeature(FImage object) { FImage image = object.getImage(); patch.analyseImage(image); @@ -131,4 +177,72 @@ class PatchExtractor implements FeatureExtractor<SparseIntFV, FImage> { return bovw.aggregate(patch.getPatchKeypoints()); } +} + + + + + + +/** + * @desc image analyser for densely sampling patches across an image + */ +class PatchFeature <IMAGE extends Image<Float, IMAGE> & SinglebandImageProcessor.Processable<Float, FImage, IMAGE>> implements ImageAnalyser<IMAGE> { + float size; + float stepx; + float stepy; + private LocalFeatureList<LocalFeatureImpl<Location, FloatFV>> patchList; + + + + /** + * @desc construct a patch sampler with given size and step + * @param size the size of the patch (a x a) + * @param stepx size of horizontal step + * @param stepy size of vertical step + */ + public PatchFeature(float size, float stepx, float stepy) { + this.size = size; + this.stepx = stepx; + this.stepy = stepy; + patchList = new MemoryLocalFeatureList<>(); + } + + + + public void analyseImage(IMAGE image) { + //clear patches of previous analysis + patchList.clear(); + + + //sample patches using sliding window provided by RectangleSampler + RectangleSampler sampler = new RectangleSampler(image, stepx, stepy, size, size); + + + Iterator<Rectangle> rects = sampler.allRectangles().iterator(); + while (rects.hasNext()) { + Rectangle rect = rects.next(); + + IMAGE rImg = image.extractROI(rect).normalise(); + + Float[] pvF = new Float[rImg.getWidth()* rImg.getHeight()]; + rImg.getPixelVector(pvF); + + float[] pvf = new float[rImg.getWidth()* rImg.getHeight()]; + for (int i = 0; i < pvF.length; i++) { pvf[i] = pvF[i].floatValue(); } + + FloatFV fv = new FloatFV(pvf); + + patchList.add(new LocalFeatureImpl<Location, FloatFV>(new SpatialLocation(rect.x, rect.y),fv)); + } + } + + + /** + * @desc returns densely sampled patches of analysed image + * @return densely sampled patches as LocalFeatureList + */ + public LocalFeatureList<LocalFeatureImpl<Location, FloatFV>> getPatchKeypoints() { + return patchList; + } } \ No newline at end of file diff --git a/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/PatchFeature.java b/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/PatchFeature.java index c5dba4ec28d285b1d9c50e38b44cbd45f96df1e5..deba08aa537b87fa6b8d42a409d1c147acb9da2d 100644 --- a/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/PatchFeature.java +++ b/visioncw3/src/main/java/uk/ac/soton/ecs/ik1g19/PatchFeature.java @@ -23,40 +23,54 @@ import org.openimaj.math.geometry.shape.Rectangle; import org.openimaj.util.array.ArrayUtils; import org.openimaj.util.pair.IntObjectPair; -public class PatchFeature <IMAGE extends Image<Float, IMAGE> & Processable<Float, FImage, IMAGE>> implements ImageAnalyser<IMAGE> { - float size; - private LocalFeatureList<LocalFeatureImpl<Location, FloatFV>> patchList; - - public PatchFeature(float size) { - this.size = size; - patchList = new MemoryLocalFeatureList<>(); - } - - public void analyseImage(IMAGE image) { - patchList.clear(); - - RectangleSampler sampler = new RectangleSampler(image, 4f, 4f, size, size); - - Iterator<Rectangle> rects = sampler.allRectangles().iterator(); - - while (rects.hasNext()) { - Rectangle rect = rects.next(); - - IMAGE rImg = image.extractROI(rect).normalise(); - - Float[] pvF = new Float[rImg.getWidth()* rImg.getHeight()]; - rImg.getPixelVector(pvF); - - float[] pvf = new float[rImg.getWidth()* rImg.getHeight()]; - for (int i = 0; i < pvF.length; i++) { pvf[i] = pvF[i].floatValue(); } - - FloatFV fv = new FloatFV(pvf); - - patchList.add(new LocalFeatureImpl<Location, FloatFV>(new SpatialLocation(rect.x, rect.y),fv)); - } - } - - public LocalFeatureList<LocalFeatureImpl<Location, FloatFV>> getPatchKeypoints() { - return patchList; - } -} +///** +// * @desc image analyser for densely sampling patches across an image +// */ +//public class PatchFeature <IMAGE extends Image<Float, IMAGE> & Processable<Float, FImage, IMAGE>> implements ImageAnalyser<IMAGE> { +// float size; +// float stepx; +// float stepy; +// private LocalFeatureList<LocalFeatureImpl<Location, FloatFV>> patchList; +// +// /** +// * +// * @param size +// * @param stepx +// * @param stepy +// */ +// public PatchFeature(float size, float stepx, float stepy) { +// this.size = size; +// this.stepx = stepx; +// this.stepy = stepy; +// patchList = new MemoryLocalFeatureList<>(); +// } +// +// +// public void analyseImage(IMAGE image) { +// patchList.clear(); +// +// RectangleSampler sampler = new RectangleSampler(image, stepx, stepy, size, size); +// +// Iterator<Rectangle> rects = sampler.allRectangles().iterator(); +// +// while (rects.hasNext()) { +// Rectangle rect = rects.next(); +// +// IMAGE rImg = image.extractROI(rect).normalise(); +// +// Float[] pvF = new Float[rImg.getWidth()* rImg.getHeight()]; +// rImg.getPixelVector(pvF); +// +// float[] pvf = new float[rImg.getWidth()* rImg.getHeight()]; +// for (int i = 0; i < pvF.length; i++) { pvf[i] = pvF[i].floatValue(); } +// +// FloatFV fv = new FloatFV(pvf); +// +// patchList.add(new LocalFeatureImpl<Location, FloatFV>(new SpatialLocation(rect.x, rect.y),fv)); +// } +// } +// +// public LocalFeatureList<LocalFeatureImpl<Location, FloatFV>> getPatchKeypoints() { +// return patchList; +// } +//}