Java tutorial
/* * 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; } */ }