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;
+//    }
+//}