/*
* 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
*/
package net.semanticmetadata.lire.benchmarking;
//import Jama.Matrix;
//import Jama.SingularValueDecomposition;
import junit.framework.TestCase;
import net.semanticmetadata.lire.imageanalysis.LireFeature;
import net.semanticmetadata.lire.impl.ChainedDocumentBuilder;
import net.semanticmetadata.lire.impl.SimpleImageSearchHits;
import net.semanticmetadata.lire.impl.SimpleResult;
import net.semanticmetadata.lire.utils.FileUtils;
import net.semanticmetadata.lire.utils.ImageUtils;
import net.semanticmetadata.lire.utils.LuceneUtils;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.FSDirectory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
/**
* User: mlux
* Date: 25.11.2009
* Time: 11:54:49
*/
public class TestGeneral extends TestCase {
// check if this directory exists!!
public String testIndex = "./temp/generaltestindex";
// public String testFiles = "C:\\Temp\\...\\images\\indexsrc\\default\\original";
public String testFiles = "C:\\Temp\\...\\images\\indexsrc\\...";
public HashMap<String, String> testcases = new HashMap<String, String>(12);
private ChainedDocumentBuilder builder;
private String queryImage;
private static boolean cutImages = false;
private double[][] mdata = null;
private ArrayList<Document> index;
protected void setUp() {
builder = new ChainedDocumentBuilder();
// builder.addBuilder(new GenericDocumentBuilder(FuzzyColorHistogram.class, "FIELD_FUZZYCOLORHIST"));
// builder.addBuilder(new GenericDocumentBuilder(JpegCoefficientHistogram.class, "FIELD_JPEGCOEFFHIST"));
// builder.addBuilder(new GenericDocumentBuilder(HSVColorHistogram.class, "FIELD_HSVCOLORHIST"));
// builder.addBuilder(new GenericDocumentBuilder(GeneralColorLayout.class, "FIELD_GENCL"));
// builder.addBuilder(DocumentBuilderFactory.getColorHistogramDocumentBuilder());
// builder.addBuilder(DocumentBuilderFactory.getCEDDDocumentBuilder());
// builder.addBuilder(DocumentBuilderFactory.getFCTHDocumentBuilder());
// builder.addBuilder(new GenericDocumentBuilder(SimpleColorHistogram.class, "FIELD_CH"));
// builder.addBuilder(new GenericDocumentBuilder(AutoColorCorrelogram.class, "FIELD_ACC"));
builder.addBuilder(DocumentBuilderFactory.getColorLayoutBuilder());
builder.addBuilder(DocumentBuilderFactory.getEdgeHistogramBuilder());
builder.addBuilder(DocumentBuilderFactory.getScalableColorBuilder());
// creating test cases ...
String testcasesDir = "C:\\Temp\\RGA\\cameraShots\\";
testcases.put(testcasesDir + "bocajr.jpg", "sb_153.jpg");
testcases.put(testcasesDir + "deskshot_01.jpg", "sb_196.jpg");
testcases.put(testcasesDir + "deskshot_02.jpg", "sb_213.jpg");
testcases.put(testcasesDir + "future.jpg", "sb_270.jpg");
testcases.put(testcasesDir + "icecrystals.jpg", "sb_219.jpg");
testcases.put(testcasesDir + "jedis.jpg", "sb_214.jpg");
// testcases.put(testcasesDir + "midnightfogs.jpg", "");
// testcases.put(testcasesDir + "myfile.jpg", "");
// testcases.put(testcasesDir + "new_01.jpg", "");
testcases.put(testcasesDir + "stussey.jpg", "sb_136.jpg");
testcases.put(testcasesDir + "supremelow.jpg", "sb_136.jpg");
testcases.put(testcasesDir + "tiffany.jpg", "sb_130.jpg");
// testcases.put(testcasesDir + "unluckys.jpg", "");
}
public void testIndex() throws IOException {
System.out.println("-< Getting files to index >--------------");
ArrayList<String> images = FileUtils.getAllImages(new File(testFiles), true);
System.out.println("-< Indexing " + images.size() + " files >--------------");
indexFiles(images, builder, testIndex);
System.out.println("-< Indexing finished >--------------");
}
private void indexFiles(ArrayList<String> images, DocumentBuilder builder, String indexPath) throws IOException {
// eventually check if the directory is there or not ...
IndexWriter iw = LuceneUtils.createIndexWriter(testIndex, false);
int count = 0;
long time = System.currentTimeMillis();
for (String identifier : images) {
// TODO: cut toes from the image ... -> doesn't work out very well. Stable at first, decreasing then.
// TODO: Joint Histogram ...
// TODO: LSA / PCA on the vectors ...-> this looks like a job for me :-D
// TODO: local features ...
Document doc = null;
if (cutImages) {
BufferedImage bimg = ImageUtils.cropImage(ImageIO.read(new FileInputStream(identifier)), 0, 0, 200, 69);
doc = builder.createDocument(bimg, identifier);
} else doc = builder.createDocument(new FileInputStream(identifier), identifier);
iw.addDocument(doc);
count++;
if (count % 100 == 0) {
int percent = (int) Math.floor(((double) count * 100.0) / (double) images.size());
double timeTemp = (double) (System.currentTimeMillis() - time) / 1000d;
int secsLeft = (int) Math.round(((timeTemp / (double) count) * (double) images.size()) - timeTemp);
System.out.println(percent + "% finished (" + count + " files), " + secsLeft + " s left");
}
}
long timeTaken = (System.currentTimeMillis() - time);
float sec = ((float) timeTaken) / 1000f;
System.out.println(sec + " seconds taken, " + (timeTaken / count) + " ms per image.");
iw.commit();
iw.close();
}
public void testPrecision() throws IOException, IllegalAccessException, InstantiationException {
int maxHits = 200;
// SimpleColorHistogram.DEFAULT_DISTANCE_FUNCTION = SimpleColorHistogram.DistanceFunction.JSD;
// computeErrorRate(ImageSearcherFactory.createColorHistogramImageSearcher(10), "Color Histogram-L2");
// System.out.println("> CEDD");
// computeErrorRate(ImageSearcherFactory.createCEDDImageSearcher(maxHits), "CEDD");
// System.out.println("> FCTH");
// computeErrorRate(ImageSearcherFactory.createFCTHImageSearcher(maxHits), "FCTH");
// System.out.println("> JCD");
// computeErrorRate(new GenericImageSearcher(maxHits, JCD.class, "FIELD_JCD"), "CEDD");
System.out.println("> FuzzyColorHist");
// computeErrorRate(new GenericImageSearcher(maxHits, FuzzyColorHistogram.class, "FIELD_FUZZYCOLORHIST"), "FuzzyColorHistogram");
// System.out.println("> JpegCoeffHist");
// computeErrorRate(new GenericImageSearcher(maxHits, JpegCoefficientHistogram.class, "FIELD_JPEGCOEFFHIST"), "JpegCoefficientHistogram");
// System.out.println("> HSVColorHistogram");
// computeErrorRate(new GenericImageSearcher(maxHits, HSVColorHistogram.class, "FIELD_HSVCOLORHIST"), "HSVColorHistogram");
// System.out.println("> SimpleColorHistogram");
// computeErrorRate(new GenericImageSearcher(maxHits, SimpleColorHistogram.class, "FIELD_CH"), "SimpleColorHistogram");
// System.out.println("> AutoColorCorrelogram");
// computeErrorRate(new GenericImageSearcher(maxHits, AutoColorCorrelogram.class, "FIELD_ACC"), "AutoColorCorrelogram");
// System.out.println("> Tamura");
// computeErrorRate(new GenericImageSearcher(maxHits, Tamura.class, "FIELD_TAMURA"), "Tamura");
// System.out.println("> GeneralColorLayout");
// computeErrorRate(new GenericImageSearcher(maxHits, GeneralColorLayout.class, "FIELD_GENCL"), "GeneralColorLayout");
// System.out.println("> ScalableColor");
// computeErrorRate(new SimpleImageSearcher(maxHits, 1.0f, 0f, 0f), "ScalableColor");
System.out.println("> ColorLayout");
computeErrorRate(ImageSearcherFactory.createColorLayoutImageSearcher(maxHits), "ColorLayout");
System.out.println("> ColorLayout (LSA)");
// computeErrorRateLsa(new SimpleImageSearcher(maxHits, 0f, 1f, 0f), "ColorLayout-Lsa");
// System.out.println("> Edgehist");
// computeErrorRate(new SimpleImageSearcher(maxHits, 0f, 0f, 1f), "EdgeHist");
}
public void computeErrorRate(ImageSearcher searcher, String prefix) throws IOException, InstantiationException, IllegalAccessException {
// int maxHits = 10;
IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(testIndex)));
for (Iterator<String> testIterator = testcases.keySet().iterator(); testIterator.hasNext(); ) {
queryImage = testIterator.next();
Document query;
if (cutImages) {
BufferedImage bimg = ImageUtils.cropImage(ImageIO.read(new FileInputStream(queryImage)), 0, 0, 200, 69);
query = builder.createDocument(new FileInputStream(queryImage), queryImage);
} else
query = builder.createDocument(new FileInputStream(queryImage), queryImage);
ImageSearchHits hits = searcher.search(query, reader);
// hits = rerank(hits, query, ColorLayout.class, DocumentBuilder.FIELD_NAME_COLORLAYOUT);
for (int i = 0; i < hits.length(); i++) {
if (hits.doc(i).get("descriptorImageIdentifier").toLowerCase().endsWith(testcases.get(queryImage))) {
System.out.println(queryImage.substring(queryImage.lastIndexOf('\\') + 1) + "-" + prefix + " -> Found at rank " + i + " (" + hits.length() + ")");
}
}
// saveToHtml(queryImage.substring(queryImage.lastIndexOf('\\') + 1) + "-" + prefix, hits, queryImage);
}
}
/*
public void computeErrorRateLsa(ImageSearcher searcher, String prefix) throws IOException, InstantiationException, IllegalAccessException {
// int maxHits = 10;
IndexReader reader = IndexReader.open(SimpleFSDirectory.open(new File(testIndex)), true);
for (Iterator<String> testIterator = testcases.keySet().iterator(); testIterator.hasNext();) {
queryImage = testIterator.next();
BufferedImage bimg = ImageIO.read(new FileInputStream(queryImage));
if (cutImages)
bimg = ImageUtils.cropImage(bimg, 0, 0, 200, 69);
ColorLayout cl = new ColorLayout();
cl.extract(bimg);
ImageSearchHits hits = lsa(reader, cl, 100);
for (int i = 0; i < hits.length(); i++) {
if (hits.doc(i).get("descriptorImageIdentifier").toLowerCase().endsWith(testcases.get(queryImage))) {
System.out.println(queryImage.substring(queryImage.lastIndexOf('\\') + 1) + "-" + prefix + " -> Found at rank " + i);
}
}
// saveToHtml(queryImage.substring(queryImage.lastIndexOf('\\') + 1) + "-" + prefix, hits, queryImage);
}
} */
private ImageSearchHits rerank(ImageSearchHits hits, Document query, Class descriptorClass, String fieldName) throws IllegalAccessException, InstantiationException {
ArrayList<SimpleResult> results = new ArrayList<SimpleResult>(hits.length());
LireFeature qf = getFeature(descriptorClass, query.getValues(fieldName)[0]);
float maxDistance = 0f;
for (int i = 0; i < hits.length(); i++) {
LireFeature lf = getFeature(descriptorClass, hits.doc(i).getValues(fieldName)[0]);
float distance = lf.getDistance(qf);
SimpleResult sr = new SimpleResult(distance, hits.doc(i), i);
results.add(sr);
maxDistance = Math.max(maxDistance, distance);
}
Collections.sort(results);
return new SimpleImageSearchHits(results, maxDistance);
}
private LireFeature getFeature(Class descriptorClass, String data) throws IllegalAccessException, InstantiationException {
LireFeature lf = (LireFeature) descriptorClass.newInstance();
if (data != null && data.length() > 0) {
lf.setStringRepresentation(data);
}
return lf;
}
private void saveToHtml(String prefix, ImageSearchHits hits, String queryImage) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("results - " + prefix + ".html"));
bw.write("<html>\n" +
"<head><title>Search Results</title></head>\n" +
"<body bgcolor=\"#FFFFFF\">\n");
bw.write("<h3>query</h3>\n");
bw.write("<a href=\"file://" + queryImage + "\"><img src=\"file://" + queryImage + "\"></a><p>\n");
bw.write("<h3>results</h3>\n");
for (int i = 0; i < hits.length(); i++) {
bw.write("<a href=\"file://" + hits.doc(i).get("descriptorImageIdentifier") + "\"><img src=\"file://" + hits.doc(i).get("descriptorImageIdentifier") + "\"></a><p>\n");
}
bw.write("</body>\n" +
"</html>");
bw.close();
}
/*
private ImageSearchHits lsa(IndexReader reader, ColorLayout query, int numDims) {
ArrayList<double[]> list = new ArrayList<double[]>(reader.numDocs());
index = new ArrayList<Document>(reader.numDocs());
int docs = reader.numDocs();
for (int i = 0; i < docs; i++) {
// bugfix by Roman Kern
if (reader.hasDeletions() && reader.isDeleted(i)) {
continue;
}
try {
Document d = reader.document(i);
String cl = d.getValues(DocumentBuilder.FIELD_NAME_COLORLAYOUT)[0];
ColorLayout cli = new ColorLayout();
cli.setStringRepresentation(cl);
double[] hist = new double[cli.getNumberOfCCoeff() * 2 + cli.getNumberOfYCoeff()];
int pos = 0;
// for (int j = 0; j < 15; j++) {
for (int j = 0; j < cli.getNumberOfYCoeff(); j++) {
hist[pos] = (double) cli.getYCoeff()[j];
pos++;
}
// for (int j = 0; j < 10; j++) {
for (int j = 0; j < cli.getNumberOfCCoeff(); j++) {
hist[pos] = (double) cli.getCbCoeff()[j];
pos++;
}
// for (int j = 0; j < 10; j++) {
for (int j = 0; j < cli.getNumberOfCCoeff(); j++) {
hist[pos] = (double) cli.getCrCoeff()[j];
pos++;
}
list.add(hist);
index.add(d);
} catch (IOException e) {
e.printStackTrace();
}
}
double[] hist = new double[query.getNumberOfCCoeff() * 2 + query.getNumberOfYCoeff()];
int pos = 0;
// for (int j = 0; j < 15; j++) {
for (int j = 0; j < query.getNumberOfYCoeff(); j++) {
hist[pos] = (double) query.getYCoeff()[j];
pos++;
}
// for (int j = 0; j < 10; j++) {
for (int j = 0; j < query.getNumberOfCCoeff(); j++) {
hist[pos] = (double) query.getCbCoeff()[j];
pos++;
}
// for (int j = 0; j < 10; j++) {
for (int j = 0; j < query.getNumberOfCCoeff(); j++) {
hist[pos] = (double) query.getCrCoeff()[j];
pos++;
}
list.add(hist);
index.add(new Document());
// System.out.println("list.size() = " + list.size());
// create matrix:
mdata = new double[list.size()][hist.length];
for (int i = 0; i < mdata.length; i++) {
mdata[i] = list.get(i);
}
Matrix m = new Matrix(mdata);
long ms = System.currentTimeMillis();
SingularValueDecomposition svd = m.svd();
ms = System.currentTimeMillis() - ms;
System.out.println("ms/1000 = " + ms / 1000);
double[] singularValues = svd.getSingularValues();
for (int i = numDims; i < singularValues.length; i++) {
singularValues[i] = 0d;
}
Matrix mNew = svd.getU().times(svd.getS()).times(svd.getV().transpose());
double[][] data = mNew.getArray();
// results:
TreeSet<SimpleResult> results = new TreeSet<SimpleResult>();
double maxDistance = 0;
double[] queryData = data[data.length - 1];
int max = data.length - 1;
// max = Math.min(max, 500);
for (int i = 0; i < max; i++) {
double[] doubles = data[i];
double distance = MetricsUtils.distL2(doubles, queryData);
results.add(new SimpleResult((float) distance, index.get(i)));
maxDistance = Math.max(maxDistance, distance);
}
ImageSearchHits hits = new SimpleImageSearchHits(results, (float) maxDistance);
return hits;
}
*/
}