import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.io.FilenameUtils; public class PicasaFaces { private static final String PARAM_OUTPUT_FOLDER = "output"; private static final String PARAM_PICASA_DB_FOLDER = "folder"; PMPDB db; HashMap<String, String> personsId; HashMap<String, ArrayList<Face>> personFaces; HashMap<Long, Image> images; public PicasaFaces(String folder) { db = new PMPDB(folder); personsId = new HashMap<String, String>(); personFaces = new HashMap<String, ArrayList<Face>>(); images = new HashMap<Long, Image>(); } public void populate() throws Exception{ db.populate(); } public void populatePersons(){ ArrayList<String> tokens = db.albumdata.get("token"); ArrayList<String> name = db.albumdata.get("name"); int nb = tokens.size(); personsId.put("0", "nobody"); for (int i=0; i<nb; i++){ String t = tokens.get(i); if(t.startsWith("]facealbum:")){ personsId.put(t.split(":")[1], name.get(i)); } } } @SuppressWarnings("static-access") public static void main(String[] args) throws Exception { Options options = new Options(); options.addOption("h","help", false, "print the help content"); options.addOption(OptionBuilder.withArgName("srcFolder").hasArg().withDescription("Picasa DB folder. Default is " + EnvironmentVariables.DEFAULT_PICASA_DB_PATH).create(PARAM_PICASA_DB_FOLDER)); options.addOption(OptionBuilder.withArgName("outputFolder").hasArg().isRequired().withDescription("output folder").create(PARAM_OUTPUT_FOLDER)); options.addOption(OptionBuilder.withArgName("replaceRegex").hasArg().withDescription("regex to change original image path if needed").create("replaceRegex")); options.addOption(OptionBuilder.withArgName("replacement").hasArg().withDescription("replacement for the regex").create("replacement")); options.addOption(new Option("prefix", "add prefix to generated face images")); options.addOption(OptionBuilder.withArgName("convert").hasArg().withDescription("path of convert from imagemagick (including convert itself)").create("convert")); CommandLineParser parser = new GnuParser(); String folder=null; String output=null; String regex=null; String replacement=null; boolean prefix =false; String convert = null; try { // parse the command line arguments CommandLine line = parser.parse( options, args ); if(line.hasOption("h")){ showHelp(options); System.exit(1); } folder = EnvironmentVariables.getPicasaDBFolder(line, PARAM_PICASA_DB_FOLDER); if(line.hasOption(PARAM_OUTPUT_FOLDER)){ output = EnvironmentVariables.expandEnvVars(line.getOptionValue(PARAM_OUTPUT_FOLDER)); if(!output.endsWith(File.separator)){ output += File.separator; } if(! new File(output).exists()){ new File(output).mkdir(); } } if(line.hasOption("replaceRegex") && !line.hasOption("replacement")){ throw new Exception("both 'replaceRegex' and 'replacement' must be present"); } if(!line.hasOption("replaceRegex") && line.hasOption("replacement")){ throw new Exception("both 'replaceRegex' and 'replacement' must be present"); } if(line.hasOption("replaceRegex") && line.hasOption("replacement")){ regex = line.getOptionValue("replaceRegex"); replacement = line.getOptionValue("replacement"); } if(line.hasOption("prefix")){ prefix=true; } if(line.hasOption("convert")){ convert=EnvironmentVariables.expandEnvVars(line.getOptionValue("convert")); } } catch( ParseException exp ) { // oops, something went wrong System.err.println( "Parsing failed. Reason: " + exp.getMessage() ); showHelp(options); System.exit(1); } PicasaFaces faces = new PicasaFaces(folder); faces.populate(); faces.populatePersons(); faces.gatherImages(); faces.processImages(regex, replacement, output, prefix, convert); } private static void showHelp(Options options) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("PicasaFaces will extract the face information from the Picasa Database and save it in a csv file. " + "If the command line contains the argument '-convert' followed by the path to convert, " + "then imagemagick will create all the face thumbshots (in the output folder with a folder for each person). " + "A string replacement of the image paths can be done if the pictures location is different from the database.", "PicasaFaces" , options , "", true); } public void gatherImages(){ long nb=db.indexes.entries; for(int i=0; i<nb; i++){ if(db.indexes.indexes.get(i).compareTo(db.indexes.folderIndex)!=0){ // not a folder String path = db.indexes.names.get(new Long(db.indexes.indexes.get(i)).intValue()) + db.indexes.names.get(i); int w = Integer.parseInt(db.imagedata.get("width").get(i)); int h = Integer.parseInt(db.imagedata.get("height").get(i)); Image img = new Image(path, i, w, h); String personName = personsId.get(db.imagedata.get("personalbumid").get(i)); if(!db.imagedata.get("facerect").get(i).equals("0000000000000001")){ img.hasFaceData=true; Face f = img.addFace(db.imagedata.get("facerect").get(i), personName ); if(!db.imagedata.get("personalbumid").get(i).equals("0")){ if(!personFaces.containsKey(personName)){ personFaces.put(personName, new ArrayList<Face>()); } personFaces.get(personName).add(f); } } images.put((long)i, img); }else{ // folder if(db.indexes.names.get(i).equals("") && db.indexes.originalIndexes.get(i).compareTo(db.indexes.folderIndex)!=0){ // reference if(i>=db.imagedata.get("personalbumid").size()){ break; } String personName = personsId.get(db.imagedata.get("personalbumid").get(i)); Long originalIndex = db.indexes.originalIndexes.get(i); if(!db.imagedata.get("facerect").get(i).equals("0000000000000001")){ images.get(originalIndex).hasChild=true; Face f = images.get(originalIndex).addFace(db.imagedata.get("facerect").get(i), personName); if(!db.imagedata.get("personalbumid").get(i).equals("0")){ if(!personFaces.containsKey(personName)){ personFaces.put(personName, new ArrayList<Face>()); } personFaces.get(personName).add(f); } } }// else folder } } } public void processImages(String regex, String replacement, String output, boolean prefix, String convert) throws IOException, InterruptedException{ StringBuilder csv = new StringBuilder("person;prefix;filename;original image path;transformed image path;image width;image height;face x;face y;face width;face height\n"); for(String person:personFaces.keySet()){ File folderPerson = new File(output+person); if(convert!=null && !folderPerson.exists()){ folderPerson.mkdir(); } int i=0; for(Face f:personFaces.get(person)){ String path; path=FilenameUtils.separatorsToSystem(f.img.path); if(regex!=null && replacement!=null){ path = path.replaceAll(regex, replacement); } int x=f.x; int y=f.y; String separator = File.separator; if(separator.equals("\\")){ separator="\\\\"; } String [] file = path.split(separator); String prefixStr = ""; if(prefix){ prefixStr = ""+ i +"_"; } String filename = output + person + File.separator + prefixStr+file[file.length-1]; if(convert!=null && new File(filename).exists()){ System.out.println("Warning, the filename already exist: "+person + File.separator + prefixStr+file[file.length-1]); } csv.append(person); csv.append(";"); if(prefix){ csv.append(i); }else{ csv.append("none"); } csv.append(";"); csv.append(file[file.length-1]); csv.append(";"); csv.append(f.img.path); csv.append(";"); csv.append(path); csv.append(";"); csv.append(f.img.w); csv.append(";"); csv.append(f.img.h); csv.append(";"); csv.append(f.x); csv.append(";"); csv.append(f.y); csv.append(";"); csv.append(f.w); csv.append(";"); csv.append(f.h); csv.append("\n"); if(convert!=null){ if(File.separator.equals("\\")){ path = "\""+path+"\""; filename = "\""+filename+"\""; } String []cmd = {convert,path, "-crop", f.w+"x"+f.h+"+"+x+"+"+y, filename}; Process p = Runtime.getRuntime().exec(cmd); p.waitFor(); } i++; } } FileWriter fw = new FileWriter(output+"faces.csv"); BufferedWriter bw = new BufferedWriter(fw); bw.write(csv.toString()); bw.close(); } }