edu.uniklu.itec.mosaix.engine.Engine.java Source code

Java tutorial

Introduction

Here is the source code for edu.uniklu.itec.mosaix.engine.Engine.java

Source

package edu.uniklu.itec.mosaix.engine;

import net.semanticmetadata.lire.builders.DocumentBuilder;
import net.semanticmetadata.lire.searchers.ImageSearchHits;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/*
 * This file is part of the Caliph and Emir project: http://www.SemanticMetadata.net.
 *
 * Caliph & Emir 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.
 *
 * Caliph & Emir 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 Caliph & Emir; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Copyright statement:
 * --------------------
 * (c) 2002-2007 by Mathias Lux (mathias@juggle.at), Lukas Esterle & Manuel Warum.
 * http://www.juggle.at, http://www.SemanticMetadata.net
 */

/**
 * The workhorse and brain of the whole application,
 * that makes use of strategies and generic sub systems.
 *
 * @author Manuel Warum
 * @author Mathias Lux, mathias@juggle.at
 * @version 0.25
 */
public final class Engine {
    private HashMap<String, Integer> file2occurence;
    private final LinkedList<WeightingStrategy> strategies_;
    private final LinkedList<EngineObserver> observer_;
    private WeightingDataFactory weightingDataFactory_;
    private static boolean outweightImageReuse = false;

    public Engine() {
        weightingDataFactory_ = new SimpleWeightingDataFactory();
        strategies_ = new LinkedList<WeightingStrategy>();
        observer_ = new LinkedList<EngineObserver>();
        file2occurence = new HashMap<String, Integer>(1000);
        // Logging.log(this, "Engine instantiated.");
    }

    /**
     * Adds a strategy to the weighting strategy collection.
     *
     * @param strategy the non-<code>null</code> strategy instance.
     */
    public void addStrategy(final WeightingStrategy strategy) {
        assert strategy != null;
        strategies_.add(strategy);
        // Logging.log(this, "Strategy added: " + strategy.getClass().getName());
    }

    /**
     * Removes the strategy from the weighting strategies
     * collection.
     *
     * @param strategy the strategy to remove.
     */
    public void removeStrategy(final WeightingStrategy strategy) {
        strategies_.remove(strategy);
        // Logging.log(this, "Strategy removed: " + strategy.getClass().getName());
    }

    public List<WeightingStrategy> getStrategies() {
        return strategies_;
    }

    /**
     * Gets all engine observers registered to the
     * engine.
     *
     * @return a list of engine observers.
     */
    public List<EngineObserver> getObservers() {
        return observer_;
    }

    /**
     * Adds an engine observer to this engine instance.
     *
     * @param observer the observer to add.
     */
    public void addObserver(EngineObserver observer) {
        assert observer != null;
        observer_.add(observer);
        // Logging.log(this, "Observer added: " + observer.getClass().getName());
    }

    /**
     * Removes an engine observer from this engine instance.
     *
     * @param observer the observer to remove.
     */
    public void removeObserver(EngineObserver observer) {
        observer_.remove(observer);
        // Logging.log(this, "Observer removed: " + observer.getClass().getName());
    }

    /**
     * <p>Evaluates the search results provided by LIRE and
     * returns the best available match.</p>
     * <p>This method takes two aspects into account: First,
     * it uses the relevancy factor as provided by LIRE;
     * second, it uses implementation instances of the
     * <code>WeightingStrategy</code> interface added to this
     * interface.</p>
     *
     * @param original        a non-<code>null</code> image instance.
     * @param hits            a non-<code>null</code> LIRE search result.
     * @param scalePercentage value from 1-100d
     * @return the best match as determined by the relevancy
     *         and the relevancy weighting.
     * @throws IOException if the image could not be loaded.
     * @see edu.uniklu.itec.mosaix.engine.WeightingStrategy
     */
    public BufferedImage findBestMatch(final BufferedImage original, final ImageSearchHits hits,
            double scalePercentage, IndexReader reader) throws IOException {
        assert original != null;
        assert hits != null;

        //BufferedImage bestImage = null;
        WeightingData bestHit = null;
        float bestRating = Float.NEGATIVE_INFINITY;

        for (int i = 0; i < hits.length(); i++) {
            Document doc = reader.document(hits.documentID(i));
            String file = doc.getField(DocumentBuilder.FIELD_NAME_IDENTIFIER).stringValue();
            //         BufferedImage repl = ImageIO.read(new File(file));
            WeightingData data = weightingDataFactory_.newInstance(doc);
            data.setRelevancy((float) hits.score(i));
            data.setSlice(original);
            data.setId(file);
            data.setScalePercentage(scalePercentage);
            //         data.setReplacement(repl);

            float weight = getWeightedRelevancy(data);
            if (outweightImageReuse) {
                if (file2occurence.containsKey(file))
                    weight *= 1f / (((float) file2occurence.get(file)) + 1f);
            }
            //         Logging.log(this, "Rated " + file + " with " + Float.toString(weight));

            if (bestRating < weight) {
                bestRating = weight;
                bestHit = data;
            }
        }

        //      Logging.log(this, "Enforcing Garbage Collection.");
        //      System.gc(); // suppose, it's badly needed now
        for (EngineObserver observer : observer_)
            observer.notifyState(bestHit, EngineObserver.USED);

        //      Logging.log(this, "Evaluation complete");
        if (outweightImageReuse) {
            if (file2occurence.containsKey(bestHit.getId()))
                file2occurence.put(bestHit.getId(), file2occurence.get(bestHit.getId()) + 1);
            else
                file2occurence.put(bestHit.getId(), 1);
        }
        return bestHit.getReplacement();
    }

    /**
     * Evaluates all weighting strategies for the
     * specified evaluation data.
     *
     * @param data the non-<code>null</code> data to evaluate.
     * @return the evaluated weighting to apply to the relevancy.
     */
    private float getWeighting(WeightingData data) {
        assert data != null;
        // Logging.log(this, "Weighting slice with " + strategies_.size() + " strategies.");
        float weight = 1.0f;
        for (WeightingStrategy strategy : strategies_)
            weight *= strategy.getFactor(data);
        return weight;
    }

    /**
     * Gets the weighted relevancy for the specified
     * weighting data instance.
     *
     * @param data the non-<code>null</code> data to evaluate.
     * @return the weighted relevancy within <code>0.0f</code>
     *         (worst case) and <code>1.0f</code> (best case).
     */
    private float getWeightedRelevancy(WeightingData data) {
        assert data != null;
        return data.getRelevancy() * getWeighting(data);
    }

    /**
     * Resets all strategies' state data to their initial
     * level.
     */
    public void reset() {
        // Logging.log(this, "Resetting state.");
        for (WeightingStrategy s : strategies_)
            s.reset();
    }

    /**
     * Switches the option if duplicate tile images (using the same images for a
     * tile more than once) should be avoided. It will still happen, but not so
     * often any more.
     *
     * @param avoid
     */
    public static void setAvoidDuplicateTileImages(boolean avoid) {
        outweightImageReuse = avoid;
    }

}