0

My purpose is to identify a shape after having trained a classifer, similar to what's done in chapter 12 of The OpenIMAJ Tutorial http://openimaj.org/tutorial/classification101.html . Chapter 12 uses Caltech101 class which is not helpful to me because I want to use my own set of images to train a classifier. I created this working code which is based on Chapter 12:

package com.mycompany.video.analytics;

import de.bwaldvogel.liblinear.SolverType;
import org.openimaj.data.DataSource;
import org.openimaj.data.dataset.Dataset;
import org.openimaj.data.dataset.GroupedDataset;
import org.openimaj.data.dataset.ListDataset;
import org.openimaj.data.dataset.VFSGroupDataset;
import org.openimaj.experiment.dataset.sampling.GroupSampler;
import org.openimaj.experiment.dataset.sampling.GroupedUniformRandomisedSampler;
import org.openimaj.experiment.dataset.split.GroupedRandomSplitter;
import org.openimaj.experiment.evaluation.classification.ClassificationEvaluator;
import org.openimaj.experiment.evaluation.classification.ClassificationResult;
import org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMAnalyser;
import org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMResult;
import org.openimaj.feature.DoubleFV;
import org.openimaj.feature.FeatureExtractor;
import org.openimaj.feature.SparseIntFV;
import org.openimaj.feature.local.data.LocalFeatureListDataSource;
import org.openimaj.feature.local.list.LocalFeatureList;
import org.openimaj.image.FImage;
import org.openimaj.image.ImageUtilities;
import org.openimaj.image.feature.dense.gradient.dsift.ByteDSIFTKeypoint;
import org.openimaj.image.feature.dense.gradient.dsift.DenseSIFT;
import org.openimaj.image.feature.dense.gradient.dsift.PyramidDenseSIFT;
import org.openimaj.image.feature.local.aggregate.BagOfVisualWords;
import org.openimaj.image.feature.local.aggregate.BlockSpatialAggregator;
import org.openimaj.io.IOUtils;
import org.openimaj.ml.annotation.ScoredAnnotation;
import org.openimaj.ml.annotation.linear.LiblinearAnnotator;
import org.openimaj.ml.clustering.ByteCentroidsResult;
import org.openimaj.ml.clustering.assignment.HardAssigner;
import org.openimaj.ml.clustering.kmeans.ByteKMeans;
import org.openimaj.util.pair.IntFloatPair;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by yschondorf on 5/29/2018.
 */
public class Chapter12Generic {
    private static String IMAGES_PATH = "C:\\Development\\Video Analytics\\tpImages";

    public static void main(String[] args) {

        try {
            LiblinearAnnotator<FImage, String> trainer = null;
            VFSGroupDataset<FImage> allData = null;
            allData = new VFSGroupDataset<FImage>(
                    IMAGES_PATH,
                    ImageUtilities.FIMAGE_READER);

            GroupedDataset<String, ListDataset<FImage>, FImage> data =
                    GroupSampler.sample(allData, 1, false);

            GroupedRandomSplitter<String, FImage> splits =
                    new GroupedRandomSplitter<String, FImage>(data, 15, 0, 15); // 15 training, 15 testing


            DenseSIFT denseSIFT = new DenseSIFT(5, 7);
            PyramidDenseSIFT<FImage> pyramidDenseSIFT = new PyramidDenseSIFT<FImage>(denseSIFT, 6f, 7);

            GroupedDataset<String, ListDataset<FImage>, FImage> sample =
                    GroupedUniformRandomisedSampler.sample(splits.getTrainingDataset(), 15);

            HardAssigner<byte[], float[], IntFloatPair> assigner = trainQuantiser(sample, pyramidDenseSIFT);

            FeatureExtractor<DoubleFV, FImage> extractor = new PHOWExtractor(pyramidDenseSIFT, assigner);

            //
            // Now we’re ready to construct and train a classifier
            //
            trainer = new LiblinearAnnotator<FImage, String>(
                    extractor, LiblinearAnnotator.Mode.MULTICLASS, SolverType.L2R_L2LOSS_SVC, 1.0, 0.00001);

            Date start = new Date();
            System.out.println("Classifier training: start");
            trainer.train(splits.getTrainingDataset());
            System.out.println("Classifier training: end");
            Date end = new Date();
            long durationSec = (end.getTime() - start.getTime()) / 1000;
            System.out.println("Classifier training duration: " + durationSec + " seconds");

            final GroupedDataset<String, ListDataset<FImage>, FImage> testDataSet = splits.getTestDataset();

            ClassificationEvaluator<CMResult<String>, String, FImage> eval =
                    new ClassificationEvaluator<CMResult<String>, String, FImage>(
                            trainer, testDataSet, new CMAnalyser<FImage, String>(CMAnalyser.Strategy.SINGLE));

            start = new Date();
            System.out.println("Classifier evaluation: start");
            Map<FImage, ClassificationResult<String>> guesses = eval.evaluate();
            System.out.println("Classifier evaluation - tp: end");
            end = new Date();
            durationSec = (end.getTime() - start.getTime()) / 1000;
            System.out.println("Classifier evaluation duration: " + durationSec + " seconds");

            CMResult<String> result = eval.analyse(guesses);
            System.out.println("Result - tp: " + result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * This method extracts the first 10000 dense SIFT features from the images in the dataset, and then clusters them
     * into 300 separate classes. The method then returns a HardAssigner which can be used to assign SIFT features to
     * identifiers
     *
     * @param pyramidDenseSIFT
     * @return
     */
    static HardAssigner<byte[], float[], IntFloatPair> trainQuantiser(
            Dataset<FImage> sample,
//            VFSGroupDataset<FImage> trainingImages,
            PyramidDenseSIFT<FImage> pyramidDenseSIFT)
    {
        System.out.println("trainQuantiser: start");
        Date start = new Date();
        List<LocalFeatureList<ByteDSIFTKeypoint>> allKeys = new ArrayList<LocalFeatureList<ByteDSIFTKeypoint>>();

        int i = 0;

        int total = sample.numInstances();
//        for (FImage image: sample) {
//            ListDataset<FImage> images = trainingImages.get(key);
//            total = images.size();
//            break;
//        }
        for (FImage rec : sample) {
            i++;
            System.out.println(String.format("Analysing image %d out of %d", i, total));
            FImage img = rec.getImage();

            pyramidDenseSIFT.analyseImage(img);
            allKeys.add(pyramidDenseSIFT.getByteKeypoints(0.005f));
        }
        final int numberOfDenseSiftFeaturesToExtract = 10000;
        final int numberOfClassesInCluster = 300;
        if (allKeys.size() > numberOfDenseSiftFeaturesToExtract)
            allKeys = allKeys.subList(0, numberOfDenseSiftFeaturesToExtract);

        ByteKMeans km = ByteKMeans.createKDTreeEnsemble(numberOfClassesInCluster);
        DataSource<byte[]> dataSource = new LocalFeatureListDataSource<ByteDSIFTKeypoint, byte[]>(allKeys);
        System.out.println(String.format(
                "Clustering %d image features into %d classes...",
                numberOfDenseSiftFeaturesToExtract, numberOfClassesInCluster));
        ByteCentroidsResult result = km.cluster(dataSource);
        Date end = new Date();
        System.out.println("trainQuantiser: end");
        System.out.println("trainQuantiser duration: " + (end.getTime() - start.getTime())/1000 + " seconds");
        return result.defaultHardAssigner();
    }

    static class PHOWExtractor implements FeatureExtractor<DoubleFV, FImage> {
        PyramidDenseSIFT<FImage> pdsift;
        HardAssigner<byte[], float[], IntFloatPair> assigner;

        public PHOWExtractor(PyramidDenseSIFT<FImage> pdsift, HardAssigner<byte[], float[], IntFloatPair> assigner)
        {
            this.pdsift = pdsift;
            this.assigner = assigner;
        }

        public DoubleFV extractFeature(FImage object) {
            FImage image = object.getImage();
            pdsift.analyseImage(image);

            BagOfVisualWords<byte[]> bovw = new BagOfVisualWords<byte[]>(assigner);

            BlockSpatialAggregator<byte[], SparseIntFV> spatial = new BlockSpatialAggregator<byte[], SparseIntFV>(
                    bovw, 2, 2);

            return spatial.aggregate(pdsift.getByteKeypoints(0.015f), image.getBounds()).normaliseFV();
        }
    }
}

The code works and produces the following output:

trainQuantiser: start
Analysing image 1 out of 15
Analysing image 2 out of 15
Analysing image 3 out of 15
Analysing image 4 out of 15
Analysing image 5 out of 15
Analysing image 6 out of 15
Analysing image 7 out of 15
Analysing image 8 out of 15
Analysing image 9 out of 15
Analysing image 10 out of 15
Analysing image 11 out of 15
Analysing image 12 out of 15
Analysing image 13 out of 15
Analysing image 14 out of 15
Analysing image 15 out of 15
Clustering 10000 image features into 300 classes...
trainQuantiser: end
trainQuantiser duration: 243 seconds
Classifier training: start
iter  1 act 6.283e-01 pre 6.283e-01 delta 1.096e+00 f 1.500e+01 |g| 1.146e+00 CG   1
iter  2 act 2.779e-05 pre 2.779e-05 delta 1.096e+00 f 1.437e+01 |g| 7.555e-03 CG   1
iter  3 act 2.175e-09 pre 2.175e-09 delta 1.096e+00 f 1.437e+01 |g| 6.702e-05 CG   1
iter  4 act 6.626e-13 pre 6.598e-13 delta 1.096e+00 f 1.437e+01 |g| 1.164e-06 CG   1
Classifier training: end
Classifier training duration: 28 seconds
Classifier evaluation: start
Classifier evaluation - tp: end
Classifier evaluation duration: 57 seconds
Result - tp:   Accuracy: 1.000
Error Rate: 0.000

I am not sure how I go from here. What I really want is not to evaluate the accuracy of the classifier - as done in chapter 12 - but rather to use the classifier in order to determine weather a new image has the shape I'm interested in. I found no documentation or example which shows how to do this. Any help would be very much appreciated.

I did not find any significant documentation except the tutorial. Could anyone to point me to where it is? Meanwhile I am just guessing. I cannot use the testDataset because there needs to be a separation between training a classifier and using it. So I would like to train the classifer once (takes a long time - many minutes) and save the result (say serialize the trainer object above to disk and deserialize it on future calls). When I am adding code to do this, and try using the testDataset on a new image I get a null pointer exception. The exception is not related to deserializing the object because I am getting the excption also when the object is not yet on the disk. New code:

package com.mycompany.video.analytics;

import de.bwaldvogel.liblinear.SolverType;
import org.apache.commons.vfs2.FileSystemException;
import org.openimaj.data.DataSource;
import org.openimaj.data.dataset.Dataset;
import org.openimaj.data.dataset.GroupedDataset;
import org.openimaj.data.dataset.ListDataset;
import org.openimaj.data.dataset.VFSGroupDataset;
import org.openimaj.experiment.dataset.sampling.GroupSampler;
import org.openimaj.experiment.dataset.sampling.GroupedUniformRandomisedSampler;
import org.openimaj.experiment.dataset.split.GroupedRandomSplitter;
import org.openimaj.experiment.evaluation.classification.ClassificationEvaluator;
import org.openimaj.experiment.evaluation.classification.ClassificationResult;
import org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMAnalyser;
import org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMResult;
import org.openimaj.feature.DoubleFV;
import org.openimaj.feature.FeatureExtractor;
import org.openimaj.feature.SparseIntFV;
import org.openimaj.feature.local.data.LocalFeatureListDataSource;
import org.openimaj.feature.local.list.LocalFeatureList;
import org.openimaj.image.FImage;
import org.openimaj.image.ImageUtilities;
import org.openimaj.image.feature.dense.gradient.dsift.ByteDSIFTKeypoint;
import org.openimaj.image.feature.dense.gradient.dsift.DenseSIFT;
import org.openimaj.image.feature.dense.gradient.dsift.PyramidDenseSIFT;
import org.openimaj.image.feature.local.aggregate.BagOfVisualWords;
import org.openimaj.image.feature.local.aggregate.BlockSpatialAggregator;
import org.openimaj.io.IOUtils;
import org.openimaj.ml.annotation.ScoredAnnotation;
import org.openimaj.ml.annotation.linear.LiblinearAnnotator;
import org.openimaj.ml.clustering.ByteCentroidsResult;
import org.openimaj.ml.clustering.assignment.HardAssigner;
import org.openimaj.ml.clustering.kmeans.ByteKMeans;
import org.openimaj.util.pair.IntFloatPair;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


public class Chapter12Generic {
    private static String IMAGES_PATH = "C:\\Development\\Video Analytics\\tpImages";
    private static String TEST_IMAGES_PATH = "C:\\Development\\Video Analytics\\testImages";
    private static String TRAINER_DATA_FILE_PATH = "C:\\Development\\Video Analytics\\out\\trainer.dat";

    public static void main(String[] args) throws Exception {

        LiblinearAnnotator<FImage, String> trainer = null;
        File inputDataFile = new File(TRAINER_DATA_FILE_PATH);
        if (inputDataFile.isFile()) {
            trainer = IOUtils.readFromFile(inputDataFile);
        } else {
            VFSGroupDataset<FImage> allData = null;
            allData = new VFSGroupDataset<FImage>(
                    IMAGES_PATH,
                    ImageUtilities.FIMAGE_READER);

            GroupedDataset<String, ListDataset<FImage>, FImage> data =
                    GroupSampler.sample(allData, 1, false);

            GroupedRandomSplitter<String, FImage> splits =
                    new GroupedRandomSplitter<String, FImage>(data, 15, 0, 15); // 15 training, 15 testing


            DenseSIFT denseSIFT = new DenseSIFT(5, 7);
            PyramidDenseSIFT<FImage> pyramidDenseSIFT = new PyramidDenseSIFT<FImage>(denseSIFT, 6f, 7);

            GroupedDataset<String, ListDataset<FImage>, FImage> sample =
                    GroupedUniformRandomisedSampler.sample(splits.getTrainingDataset(), 15);

            HardAssigner<byte[], float[], IntFloatPair> assigner = trainQuantiser(sample, pyramidDenseSIFT);

            FeatureExtractor<DoubleFV, FImage> extractor = new PHOWExtractor(pyramidDenseSIFT, assigner);

            //
            // Now we’re ready to construct and train a classifier
            //
            trainer = new LiblinearAnnotator<FImage, String>(
                    extractor, LiblinearAnnotator.Mode.MULTICLASS, SolverType.L2R_L2LOSS_SVC, 1.0, 0.00001);

            Date start = new Date();
            System.out.println("Classifier training: start");
            trainer.train(splits.getTrainingDataset());
            IOUtils.writeToFile(trainer, inputDataFile);

            System.out.println("Classifier training: end");
            Date end = new Date();
            long durationSec = (end.getTime() - start.getTime()) / 1000;
            System.out.println("Classifier training duration: " + durationSec + " seconds");
        }

//        final GroupedDataset<String, ListDataset<FImage>, FImage> testDataSet = splits.getTestDataset();
        VFSGroupDataset<FImage> testDataSet = new VFSGroupDataset<FImage>(
                TEST_IMAGES_PATH,
                ImageUtilities.FIMAGE_READER);

        ClassificationEvaluator<CMResult<String>, String, FImage> eval =
                new ClassificationEvaluator<CMResult<String>, String, FImage>(
                        trainer, testDataSet, new CMAnalyser<FImage, String>(CMAnalyser.Strategy.SINGLE));

        Date start = new Date();
        System.out.println("Classifier evaluation: start");
        Map<FImage, ClassificationResult<String>> guesses = eval.evaluate();
        System.out.println("Classifier evaluation - tp: end");
        Date end = new Date();
        long durationSec = (end.getTime() - start.getTime()) / 1000;
        System.out.println("Classifier evaluation duration: " + durationSec + " seconds");

        CMResult<String> result = eval.analyse(guesses);
        System.out.println("Result - tp: " + result);      
    }

    /**
     * This method extracts the first 10000 dense SIFT features from the images in the dataset, and then clusters them
     * into 300 separate classes. The method then returns a HardAssigner which can be used to assign SIFT features to
     * identifiers
     *
     * @param pyramidDenseSIFT
     * @return
     */
    static HardAssigner<byte[], float[], IntFloatPair> trainQuantiser(
            Dataset<FImage> sample,
//            VFSGroupDataset<FImage> trainingImages,
            PyramidDenseSIFT<FImage> pyramidDenseSIFT)
    {
        System.out.println("trainQuantiser: start");
        Date start = new Date();
        List<LocalFeatureList<ByteDSIFTKeypoint>> allKeys = new ArrayList<LocalFeatureList<ByteDSIFTKeypoint>>();

        int i = 0;

        int total = sample.numInstances();
//        for (FImage image: sample) {
//            ListDataset<FImage> images = trainingImages.get(key);
//            total = images.size();
//            break;
//        }
        for (FImage rec : sample) {
            i++;
            System.out.println(String.format("Analysing image %d out of %d", i, total));
            FImage img = rec.getImage();

            pyramidDenseSIFT.analyseImage(img);
            allKeys.add(pyramidDenseSIFT.getByteKeypoints(0.005f));
        }
        final int numberOfDenseSiftFeaturesToExtract = 10000;
        final int numberOfClassesInCluster = 300;
        if (allKeys.size() > numberOfDenseSiftFeaturesToExtract)
            allKeys = allKeys.subList(0, numberOfDenseSiftFeaturesToExtract);

        ByteKMeans km = ByteKMeans.createKDTreeEnsemble(numberOfClassesInCluster);
        DataSource<byte[]> dataSource = new LocalFeatureListDataSource<ByteDSIFTKeypoint, byte[]>(allKeys);
        System.out.println(String.format(
                "Clustering %d image features into %d classes...",
                numberOfDenseSiftFeaturesToExtract, numberOfClassesInCluster));
        ByteCentroidsResult result = km.cluster(dataSource);
        Date end = new Date();
        System.out.println("trainQuantiser: end");
        System.out.println("trainQuantiser duration: " + (end.getTime() - start.getTime())/1000 + " seconds");
        return result.defaultHardAssigner();
    }

    static class PHOWExtractor implements FeatureExtractor<DoubleFV, FImage> {
        PyramidDenseSIFT<FImage> pdsift;
        HardAssigner<byte[], float[], IntFloatPair> assigner;

        public PHOWExtractor(PyramidDenseSIFT<FImage> pdsift, HardAssigner<byte[], float[], IntFloatPair> assigner)
        {
            this.pdsift = pdsift;
            this.assigner = assigner;
        }

        public DoubleFV extractFeature(FImage object) {
            FImage image = object.getImage();
            pdsift.analyseImage(image);

            BagOfVisualWords<byte[]> bovw = new BagOfVisualWords<byte[]>(assigner);

            BlockSpatialAggregator<byte[], SparseIntFV> spatial = new BlockSpatialAggregator<byte[], SparseIntFV>(
                    bovw, 2, 2);

            return spatial.aggregate(pdsift.getByteKeypoints(0.015f), image.getBounds()).normaliseFV();
        }
    }
}

Exception:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:130)
Caused by: java.lang.NullPointerException
    at org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMAnalyser$Strategy$1.add(CMAnalyser.java:80)
    at org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMAnalyser.analyse(CMAnalyser.java:172)
    at org.openimaj.experiment.evaluation.classification.analysers.confusionmatrix.CMAnalyser.analyse(CMAnalyser.java:57)
    at org.openimaj.experiment.evaluation.classification.ClassificationEvaluator.analyse(ClassificationEvaluator.java:190)
    at com.mycompany.video.analytics.Chapter12Generic.main(Chapter12Generic.java:113)

Exception happens at the call to

CMResult<String> result = eval.analyse(guesses);

Any ideas how to fix this?

Adding version 3 of the code based on @jon's answer. The problem now is that it classifies a false image as true.

public class Chapter12Generic_v3 {

    // contains an accordion folder with images from caltech101
    private static String TRAINING_IMAGES_PATH = "C:\\Development\\Video Analytics\\images";

    // contains 1 airplane image from caltech101
    private static String TEST_IMAGE = "C:\\Development\\Video Analytics\\testImages\\falseImages\\image_0001.jpg";

    private static String TRAINER_DATA_FILE_PATH = "C:\\Development\\Video Analytics\\out\\trainer.dat";

    public static void main(String[] args) throws Exception {
        LiblinearAnnotator<FImage, String> trainer = null;
        File inputDataFile = new File(TRAINER_DATA_FILE_PATH);
        if (inputDataFile.isFile()) {
            trainer = IOUtils.readFromFile(inputDataFile);
        } else {
            VFSGroupDataset<FImage> allData = null;
            allData = new VFSGroupDataset<FImage>(
                    TRAINING_IMAGES_PATH,
                    ImageUtilities.FIMAGE_READER);

            GroupedDataset<String, ListDataset<FImage>, FImage> data =
                    GroupSampler.sample(allData, 1, false);

            GroupedRandomSplitter<String, FImage> splits =
                    new GroupedRandomSplitter<String, FImage>(data, 15, 0, 15); // 15 training, 15 testing


            DenseSIFT denseSIFT = new DenseSIFT(5, 7);
            PyramidDenseSIFT<FImage> pyramidDenseSIFT = new PyramidDenseSIFT<FImage>(denseSIFT, 6f, 7);

            GroupedDataset<String, ListDataset<FImage>, FImage> sample =
                    GroupedUniformRandomisedSampler.sample(splits.getTrainingDataset(), 15);

            HardAssigner<byte[], float[], IntFloatPair> assigner = trainQuantiser(sample, pyramidDenseSIFT);

            FeatureExtractor<DoubleFV, FImage> extractor = new PHOWExtractor(pyramidDenseSIFT, assigner);

            //
            // Now we’re ready to construct and train a classifier
            //
            trainer = new LiblinearAnnotator<FImage, String>(
                    extractor, LiblinearAnnotator.Mode.MULTICLASS, SolverType.L2R_L2LOSS_SVC, 1.0, 0.00001);

            Date start = new Date();
            System.out.println("Classifier training: start");
            trainer.train(splits.getTrainingDataset());
            IOUtils.writeToFile(trainer, new File(TRAINER_DATA_FILE_PATH));
            System.out.println("Classifier training: end");
            Date end = new Date();
            long durationSec = (end.getTime() - start.getTime()) / 1000;
            System.out.println("Classifier training duration: " + durationSec + " seconds");
        }


        FImage query = ImageUtilities.readF(new File(TEST_IMAGE));

        final List<ScoredAnnotation<String>> scoredAnnotations = trainer.annotate(query);
        final ClassificationResult<String> classificationResult = trainer.classify(query);
        System.out.println("scoredAnnotations: " + scoredAnnotations);
        System.out.println("classificationResult: " + classificationResult);
    }

    /**
     * This method extracts the first 10000 dense SIFT features from the images in the dataset, and then clusters them
     * into 300 separate classes. The method then returns a HardAssigner which can be used to assign SIFT features to
     * identifiers
     *
     * @param pyramidDenseSIFT
     * @return
     */
    static HardAssigner<byte[], float[], IntFloatPair> trainQuantiser(
            Dataset<FImage> sample,
            PyramidDenseSIFT<FImage> pyramidDenseSIFT)
    {
        System.out.println("trainQuantiser: start");
        Date start = new Date();
        List<LocalFeatureList<ByteDSIFTKeypoint>> allKeys = new ArrayList<LocalFeatureList<ByteDSIFTKeypoint>>();

        int i = 0;

        int total = sample.numInstances();
        for (FImage rec : sample) {
            i++;
            System.out.println(String.format("Analysing image %d out of %d", i, total));
            FImage img = rec.getImage();

            pyramidDenseSIFT.analyseImage(img);
            allKeys.add(pyramidDenseSIFT.getByteKeypoints(0.005f));
        }
        final int numberOfDenseSiftFeaturesToExtract = 10000;
        final int numberOfClassesInCluster = 300;
        if (allKeys.size() > numberOfDenseSiftFeaturesToExtract)
            allKeys = allKeys.subList(0, numberOfDenseSiftFeaturesToExtract);

        ByteKMeans km = ByteKMeans.createKDTreeEnsemble(numberOfClassesInCluster);
        DataSource<byte[]> dataSource = new LocalFeatureListDataSource<ByteDSIFTKeypoint, byte[]>(allKeys);
        System.out.println(String.format(
                "Clustering %d image features into %d classes...",
                numberOfDenseSiftFeaturesToExtract, numberOfClassesInCluster));
        ByteCentroidsResult result = km.cluster(dataSource);
        Date end = new Date();
        System.out.println("trainQuantiser: end");
        System.out.println("trainQuantiser duration: " + (end.getTime() - start.getTime())/1000 + " seconds");
        return result.defaultHardAssigner();
    }

    static class PHOWExtractor implements FeatureExtractor<DoubleFV, FImage> {
        PyramidDenseSIFT<FImage> pdsift;
        HardAssigner<byte[], float[], IntFloatPair> assigner;

        public PHOWExtractor(PyramidDenseSIFT<FImage> pdsift, HardAssigner<byte[], float[], IntFloatPair> assigner)
        {
            this.pdsift = pdsift;
            this.assigner = assigner;
        }

        public DoubleFV extractFeature(FImage object) {
            FImage image = object.getImage();
            pdsift.analyseImage(image);

            BagOfVisualWords<byte[]> bovw = new BagOfVisualWords<byte[]>(assigner);

            BlockSpatialAggregator<byte[], SparseIntFV> spatial = new BlockSpatialAggregator<byte[], SparseIntFV>(
                    bovw, 2, 2);

            return spatial.aggregate(pdsift.getByteKeypoints(0.015f), image.getBounds()).normaliseFV();
        }
    }
}
Jacobs2000
  • 856
  • 2
  • 15
  • 25
  • you got a testDataset right there - I dont know thats were the test images reside - so you've got to stick your images in there - and you have to go through the documentation – gpasch Oct 13 '18 at 02:05
  • @gpasch I updated the question based on your comment. I did not find any significant documentation except the tutorial. And I cannot use the testDataset because I want to separate the training part from the detection part, and new code throws a NullPointerException. – Jacobs2000 Oct 13 '18 at 06:55
  • I'm concentrating on this ClassificationEvaluator, String, FImage> eval = new ClassificationEvaluator, String, FImage>( trainer, testDataSet, new CMAnalyser(CMAnalyser.Strategy.SINGLE)); -- you have to look into ClassificationEvaluator in the documentation dont expect everything from tutorials- so yes you do the training and store the result. Then test with whatever you want - replace the whole test set if it has to be – gpasch Oct 13 '18 at 07:07
  • Well, the only documentation I could find is the API reference http://openimaj.org/apidocs/org/openimaj/experiment/evaluation/classification/ClassificationEvaluator.html . eval has 2 methods I can use: evaluate() and analyse(Map> predicted) So I should execute them sequentially: Map> guesses = eval.evaluate(); CMResult result = eval.analyse(guesses); but the second call throws an exception as I already mentioned... – Jacobs2000 Oct 13 '18 at 09:51

1 Answers1

1

If you just want to classify things with the model you've trained then ignore all the ClassificationEvaluator stuff - its just for computing accuracy, etc.

Take a look at http://openimaj.org/apidocs/org/openimaj/ml/annotation/linear/LiblinearAnnotator.html (the type of your trainer object). As your trainer instance is typed on FImage and String its annotate() and classify() methods will both accept an FImage that you provide as input and provide the classification result as output (in slightly different forms; you'll have to decide which fits your needs best).

Jon
  • 841
  • 4
  • 5
  • I added version 3 of the code, based on your answer @Jon. The main change is instantiating a single FImage, and calling trainer.annotate(). The problem now is that I put an airplane test image, but it is classified as accordion. TRAINING_IMAGES_PATH contains a single accordion folder with accordion images from caltech101 (http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz) . TEST_IMAGE contains 1 airplane image from caltech101. What is still not right? – Jacobs2000 Oct 22 '18 at 09:31
  • You can't just train it on a single class - at a minimum you need to have one negative class with example images during training – Jon Oct 30 '18 at 22:02
  • You are right! I added another folder for airplane, changed the line GroupedDataset, FImage> data = GroupSampler.sample(allData, 1, false); to GroupedDataset, FImage> data = GroupSampler.sample(allData, 2, false); and surely enough the airplane image was classified correctly. – Jacobs2000 Oct 31 '18 at 09:40