net.semanticmetadata.lire.impl.SimpleBuilder.java Source code

Java tutorial

Introduction

Here is the source code for net.semanticmetadata.lire.impl.SimpleBuilder.java

Source

/*
 * This file is part of the LIRE project: http://www.semanticmetadata.net/lire
 * LIRE is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * LIRE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LIRE; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * We kindly ask you to refer the any or one of the following publications in
 * any publication mentioning or employing Lire:
 *
 * Lux Mathias, Savvas A. Chatzichristofis. Lire: Lucene Image Retrieval 
 * An Extensible Java CBIR Library. In proceedings of the 16th ACM International
 * Conference on Multimedia, pp. 1085-1088, Vancouver, Canada, 2008
 * URL: http://doi.acm.org/10.1145/1459359.1459577
 *
 * Lux Mathias. Content Based Image Retrieval with LIRE. In proceedings of the
 * 19th ACM International Conference on Multimedia, pp. 735-738, Scottsdale,
 * Arizona, USA, 2011
 * URL: http://dl.acm.org/citation.cfm?id=2072432
 *
 * Mathias Lux, Oge Marques. Visual Information Retrieval using Java and LIRE
 * Morgan & Claypool, 2013
 * URL: http://www.morganclaypool.com/doi/abs/10.2200/S00468ED1V01Y201301ICR025
 *
 * Copyright statement:
 * ====================
 * (c) 2002-2013 by Mathias Lux (mathias@juggle.at)
 *  http://www.semanticmetadata.net/lire, http://www.lire-project.net
 *
 * Updated: 13.02.15 18:52
 */

package net.semanticmetadata.lire.impl;

import net.semanticmetadata.lire.DocumentBuilder;
import net.semanticmetadata.lire.imageanalysis.CEDD;
import net.semanticmetadata.lire.imageanalysis.ScalableColor;
import net.semanticmetadata.lire.imageanalysis.opencvfeatures.CvSiftExtractor;
import net.semanticmetadata.lire.imageanalysis.opencvfeatures.CvSiftFeature;
import net.semanticmetadata.lire.imageanalysis.opencvfeatures.CvSurfExtractor;
import net.semanticmetadata.lire.imageanalysis.opencvfeatures.CvSurfFeature;
import net.semanticmetadata.lire.AbstractDocumentBuilder;
import net.semanticmetadata.lire.imageanalysis.LireFeature;
import net.semanticmetadata.lire.utils.ImageUtils;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

/**
 * Implementation based on the paper Searching Images with MPEG-7 (& MPEG-7-like) Powered Localized
 * dEscriptors: The SIMPLE answer to effective Content Based Image Retrieval (Savvas Chatzichristofis
 * sent me the code :))
 * Created by mlux on 13.06.2014.
 */
public class SimpleBuilder extends AbstractDocumentBuilder {
    public static final int MAX_IMAGE_DIMENSION = 1024;
    public static final String Detector_CVSURF = "detCVSURF";
    public static final String Detector_CVSIFT = "detCVSIFT";
    public static final String Detector_RANDOM = "detRandom";
    public static final String Detector_GAUSSRANDOM = "detGaussRandom";

    private LireFeature lireFeature = new CEDD();
    private KeypointDetector kpdetect = KeypointDetector.Random;

    public enum KeypointDetector {
        CVSURF, CVSIFT, Random, GaussRandom
    };

    private int samples = 600;

    final int[] sizeLookUp = new int[] { 40, (int) (40 * 1.6), (int) (40 * 2.3), 40 * 3 };

    public SimpleBuilder() {
    }

    /**
     * Set the Local Descriptor feature to the one given.
     * @param lireFeature
     */
    public SimpleBuilder(LireFeature lireFeature) {
        this.lireFeature = lireFeature;
    }

    public SimpleBuilder(LireFeature lireFeature, KeypointDetector detector) {
        this.kpdetect = detector;
        this.lireFeature = lireFeature;
    }

    public SimpleBuilder(LireFeature lireFeature, KeypointDetector detector, int numOfSamplesInCaseOfRandom) {
        this.kpdetect = detector;
        this.lireFeature = lireFeature;
        this.samples = numOfSamplesInCaseOfRandom;
    }

    @Override
    public Field[] createDescriptorFields(BufferedImage image) {
        BufferedImage bimg = image;
        // Scaling image is especially with the correlogram features very important!
        // All images are scaled to guarantee a certain upper limit for indexing.
        if (Math.max(image.getHeight(), image.getWidth()) > MAX_IMAGE_DIMENSION) {
            bimg = ImageUtils.scaleImage(image, MAX_IMAGE_DIMENSION);
        }
        if (kpdetect == KeypointDetector.CVSURF) {
            return useCVSURF(bimg);
        } else if (kpdetect == KeypointDetector.CVSIFT) {
            return useCVSIFT(bimg);
        } else if (kpdetect == KeypointDetector.Random) {
            return useRandom(bimg);
        } else if (kpdetect == KeypointDetector.GaussRandom) {
            return useGaussRandom(bimg);
        } else
            throw new UnsupportedOperationException("Something was wrong in setting the desired detector");
    }

    private Field[] useCVSURF(BufferedImage image) {
        ArrayList<Field> fields = new ArrayList<Field>();
        CvSurfExtractor extractor = new CvSurfExtractor();
        LinkedList<CvSurfFeature> descriptors = extractor.computeSurfKeypoints(image);
        CvSurfFeature next;
        for (Iterator<CvSurfFeature> iterator = descriptors.iterator(); iterator.hasNext();) {
            next = iterator.next();
            lireFeature.extract(ImageUtils.cropImage(image, (int) (next.point[0] - (int) next.size / 2),
                    (int) (next.point[1] - (int) next.size / 2), (int) next.size, (int) next.size));
            fields.add(new StoredField(
                    DocumentBuilder.FIELD_NAME_SIMPLE + lireFeature.getFieldName() + Detector_CVSURF,
                    lireFeature.getByteArrayRepresentation()));
        }
        return fields.toArray(new Field[fields.size()]);
    }

    private Field[] useCVSIFT(BufferedImage image) {
        ArrayList<Field> fields = new ArrayList<Field>();
        CvSiftExtractor extractor = new CvSiftExtractor();
        LinkedList<CvSiftFeature> descriptors = extractor.computeSiftKeypoints(image);
        CvSiftFeature next;
        for (Iterator<CvSiftFeature> iterator = descriptors.iterator(); iterator.hasNext();) {
            next = iterator.next();
            lireFeature.extract(ImageUtils.cropImage(image, (int) (next.point[0] - (int) next.size / 2),
                    (int) (next.point[1] - (int) next.size / 2), (int) next.size, (int) next.size));
            fields.add(new StoredField(
                    DocumentBuilder.FIELD_NAME_SIMPLE + lireFeature.getFieldName() + Detector_CVSIFT,
                    lireFeature.getByteArrayRepresentation()));
        }
        return fields.toArray(new Field[fields.size()]);
    }

    private Field[] useRandom(BufferedImage image) {
        ArrayList<Field> fields = new ArrayList<Field>();
        //        LinkedList<keypoint> keypointsList = createRndPts(image.getWidth(), image.getHeight(), samples);
        //        keypoint next;
        // opting in for more performance: no "new" for creating key points, no String concat in the loop. (ml)
        int[] myKeypoint = new int[3];
        Random r = new Random();
        String fieldName = DocumentBuilder.FIELD_NAME_SIMPLE + lireFeature.getFieldName() + Detector_RANDOM;
        for (int i = 0; i < samples; i++) {
            createNextRandomPoint(myKeypoint, image.getWidth(), image.getHeight(), r);
            lireFeature.extract(
                    ImageUtils.cropImage(image, myKeypoint[0], myKeypoint[1], myKeypoint[2], myKeypoint[2]));
            fields.add(new StoredField(fieldName, lireFeature.getByteArrayRepresentation()));

        }
        //        for (Iterator<keypoint> iterator = keypointsList.iterator(); iterator.hasNext(); ) {
        //            next = iterator.next();
        //            lireFeature.extract(ImageUtils.cropImage(image, (int) (next.X), (int) (next.Y), (int) next.Size, (int) next.Size));
        //            fields.add(new StoredField(DocumentBuilder.FIELD_NAME_SIMPLE + lireFeature.getFieldName() + Detector_RANDOM, lireFeature.getByteArrayRepresentation()));
        //        }
        return fields.toArray(new Field[fields.size()]);
    }

    private Field[] useGaussRandom(BufferedImage image) {
        ArrayList<Field> fields = new ArrayList<Field>();
        LinkedList<keypoint> keypointsList = createGaussRndPts(image.getWidth(), image.getHeight(), samples);
        keypoint next;
        String fieldName = DocumentBuilder.FIELD_NAME_SIMPLE + lireFeature.getFieldName() + Detector_GAUSSRANDOM;
        for (Iterator<keypoint> iterator = keypointsList.iterator(); iterator.hasNext();) {
            next = iterator.next();
            lireFeature.extract(ImageUtils.cropImage(image, (int) (next.X - (next.Size / 2)),
                    (int) (next.Y - (next.Size / 2)), (int) next.Size, (int) next.Size));
            fields.add(new StoredField(fieldName, lireFeature.getByteArrayRepresentation()));
        }
        return fields.toArray(new Field[fields.size()]);
    }

    private LinkedList<keypoint> createRndPts(int width, int height, int samples) {
        Random ran = new Random();
        int size = -1;
        keypoint key;
        LinkedList<keypoint> keypointsList = new LinkedList<keypoint>();
        for (int i = 0; i < samples; i++) {
            //            sizeTemp = ran.nextInt(4);
            //            if (sizeTemp == 0) {
            //                size = 40;
            //            } else if (sizeTemp == 1) {
            //                size = (int) (40 * 1.6);
            //            } else if (sizeTemp == 2) {
            //                size = (int) (40 * 2.3);
            //            } else if (sizeTemp == 3) {
            //                size = (int) (40 * 3);
            //            }
            size = sizeLookUp[ran.nextInt(4)];
            key = new keypoint(ran.nextInt(width - size), ran.nextInt(height - size), size);
            //            System.out.println("(" + (key.X) + "," + (key.Y) + ")\t" + key.Size);
            keypointsList.add(key);
        }

        return keypointsList;
    }

    private void createNextRandomPoint(int[] myKeypoint, int width, int height, Random random) {
        myKeypoint[2] = sizeLookUp[random.nextInt(4)];
        myKeypoint[0] = random.nextInt(width - myKeypoint[2]);
        myKeypoint[1] = random.nextInt(height - myKeypoint[2]);
    }

    private LinkedList<keypoint> createGaussRndPts(int width, int height, int samples) {
        Random ran = new Random();

        double seedWidth = (width / 4) - 10;
        double seedHeight = (height / 4) - 10;
        double meanWidth = width / 2;
        double meanHeight = height / 2;

        int size = -1;
        int sizeTemp, sizeLimit, widthLimit, heightLimit;
        int x, y;
        keypoint key;
        LinkedList<keypoint> keypointsList = new LinkedList<keypoint>();
        for (int i = 0; i < samples; i++) {
            //            sizeTemp = ran.nextInt(4);
            //            if (sizeTemp == 0) {
            //                size = 40;
            //            } else if (sizeTemp == 1) {
            //                size = (int) (40 * 1.6);
            //            } else if (sizeTemp == 2) {
            //                size = (int) (40 * 2.3);
            //            } else if (sizeTemp == 3) {
            //                size = (int) (40 * 3);
            //            }
            size = sizeLookUp[ran.nextInt(4)];
            sizeLimit = size / 2;
            widthLimit = width - sizeLimit;
            heightLimit = height - sizeLimit;

            //TODO: change do...while
            do {
                x = (int) (ran.nextGaussian() * seedWidth + meanWidth);
            } while (!((x > sizeLimit) && (x < widthLimit)));
            do {
                y = (int) (ran.nextGaussian() * seedHeight + meanHeight);
            } while (!((y > sizeLimit) && (y < heightLimit)));

            key = new keypoint(x, y, size);
            //            System.out.println("(" + (key.X) + "," + (key.Y) + ")\t" + key.Size);
            keypointsList.add(key);
        }

        return keypointsList;
    }

    public String getDetector(KeypointDetector detector) {
        if (detector == KeypointDetector.CVSURF) {
            return Detector_CVSURF;
        } else if (detector == KeypointDetector.CVSIFT) {
            return Detector_CVSIFT;
        } else if (detector == KeypointDetector.Random) {
            return Detector_RANDOM;
        } else if (detector == KeypointDetector.GaussRandom) {
            return Detector_GAUSSRANDOM;
        } else
            throw new UnsupportedOperationException("Something was wrong in returning the used detector");
    }

    public String getFieldName(KeypointDetector detector, LireFeature feature) {
        if (detector == KeypointDetector.CVSURF) {
            return DocumentBuilder.FIELD_NAME_SIMPLE + feature.getFieldName() + getDetector(detector);
        } else if (detector == KeypointDetector.CVSIFT) {
            return DocumentBuilder.FIELD_NAME_SIMPLE + feature.getFieldName() + getDetector(detector);
        } else if (detector == KeypointDetector.Random) {
            return DocumentBuilder.FIELD_NAME_SIMPLE + feature.getFieldName() + getDetector(detector);
        } else if (detector == KeypointDetector.GaussRandom) {
            return DocumentBuilder.FIELD_NAME_SIMPLE + feature.getFieldName() + getDetector(detector);
        } else
            throw new UnsupportedOperationException("Something was wrong in returning the used detector");
    }

    private class keypoint {
        public int X;
        public int Y;
        public int Size;

        public keypoint(int xx, int yy, int s) {
            X = xx;
            Y = yy;
            Size = s;
        }
    }
}