001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image.processing.face.recognition.benchmarking.dataset; 031 032import java.io.BufferedReader; 033import java.io.BufferedWriter; 034import java.io.File; 035import java.io.FileReader; 036import java.io.FileWriter; 037import java.io.IOException; 038import java.util.AbstractList; 039import java.util.ArrayList; 040import java.util.List; 041 042import org.apache.log4j.Logger; 043import org.openimaj.data.dataset.ListBackedDataset; 044import org.openimaj.data.dataset.ListDataset; 045import org.openimaj.data.dataset.MapBackedDataset; 046import org.openimaj.image.FImage; 047import org.openimaj.image.ImageUtilities; 048 049/** 050 * A simple dataset of people and their images, backed by a 051 * text file with the following format: 052 * <pre> 053 * personA,/path/to/image.jpg 054 * personA,/path/to/image1.jpg 055 * personB,/path/to/image2.jpg 056 * ... 057 * </pre> 058 * 059 * The default separator is a comma, but is user controllable. 060 * <p> 061 * In addition to allowing datasets to be read from a file, this 062 * implementation also allows datasets to be created or appended 063 * to through the {@link #add(String, File)} method. 064 * 065 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 066 * 067 */ 068public class TextFileDataset extends MapBackedDataset<String, ListDataset<FImage>, FImage> { 069 private class LazyImageList extends AbstractList<FImage> { 070 List<File> files = new ArrayList<File>(); 071 072 @Override 073 public FImage get(int index) { 074 File f = files.get(index); 075 076 if (f.isAbsolute()) { 077 try { 078 return ImageUtilities.readF(f); 079 } catch (IOException e) { 080 logger.warn(e); 081 return null; 082 } 083 } else { 084 try { 085 return ImageUtilities.readF(new File(file.getParentFile(), f.toString())); 086 } catch (IOException e) { 087 logger.warn(e); 088 return null; 089 } 090 } 091 } 092 093 @Override 094 public int size() { 095 return files.size(); 096 } 097 098 @Override 099 public String toString() { 100 return files.toString(); 101 } 102 } 103 104 private static final Logger logger = Logger.getLogger(TextFileDataset.class); 105 private String separator = ","; 106 File file; 107 BufferedWriter writer; 108 109 /** 110 * Construct from the given file. The default separator 111 * of a comma "," will be used. 112 * 113 * @param file the file 114 * @throws IOException if an error occurs 115 */ 116 public TextFileDataset(File file) throws IOException { 117 this(file, ","); 118 } 119 120 /** 121 * Construct from the given file, using the given separator. 122 * @param file the file 123 * @param separator the separator 124 * @throws IOException if an error occurs 125 */ 126 public TextFileDataset(File file, String separator) throws IOException { 127 this.file = file; 128 this.separator = separator; 129 130 if (file.exists()) 131 read(); 132 else 133 openWriter(); 134 } 135 136 /* (non-Javadoc) 137 * @see java.lang.Object#finalize() 138 */ 139 @Override 140 protected void finalize() throws Throwable { 141 if (writer != null) { 142 try { writer.close(); } catch (IOException e) {} 143 } 144 145 super.finalize(); 146 } 147 148 private void read() throws IOException { 149 BufferedReader br = null; 150 151 try { 152 br = new BufferedReader(new FileReader(file)); 153 154 String line; 155 while ((line = br.readLine()) != null) { 156 String[] parts = line.split(separator); 157 158 addInternal(parts[0].trim(), new File (parts[1].trim())); 159 } 160 } finally { 161 if (br != null) try { br.close(); } catch (IOException e) {} 162 } 163 } 164 165 private void addInternal(String person, File file) { 166 ListBackedDataset<FImage> list = (ListBackedDataset<FImage>) map.get(person); 167 168 if (list == null) map.put(person, list = new ListBackedDataset<FImage>(new LazyImageList())); 169 ((LazyImageList)list.getList()).files.add(file); 170 } 171 172 /** 173 * Add an instance to the dataset. 174 * 175 * @param person 176 * @param file 177 * @throws IOException 178 */ 179 public void add(String person, File file) throws IOException { 180 if (writer == null) 181 openWriter(); 182 183 writer.write(person+separator+file.getAbsolutePath()+"\n"); 184 writer.flush(); 185 186 addInternal(person, file); 187 } 188 189 private void openWriter() throws IOException { 190 try { 191 writer = new BufferedWriter(new FileWriter(file, true)); 192 } catch (IOException e) { 193 writer = null; 194 throw e; 195 } 196 } 197 198 @Override 199 public String toString() { 200 return "Text File Dataset (" + file + ")"; 201 } 202}