package net.semanticmetadata.lire.indexers.tools.text;
import net.semanticmetadata.lire.imageanalysis.features.GlobalFeature;
import net.semanticmetadata.lire.indexers.parallel.WorkItem;
import net.semanticmetadata.lire.utils.CommandLineUtils;
import net.semanticmetadata.lire.utils.StatsUtils;
import org.apache.commons.io.IOUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Simple command line tool for extraction of image
* feature from image files given by a list.
*
* @autor Mathias Lux
*/
public class ParallelExtraction implements Runnable {
private static String helpMessage = "Use with -i <infile> -o <outfile> -c CEDD,FCTH,PHOG";
private File imageList;
private File outFile;
private ArrayList<GlobalFeature> listOfFeatures = new ArrayList<>();
private int numOfThreads = 8;
private int overallCount = 0;
private LinkedBlockingQueue<WorkItem> queue = new LinkedBlockingQueue<>(5000);
private long monitoringInterval = 10;
private OutputStream dos;
public static void main(String[] args) {
Properties cmd = CommandLineUtils.getProperties(args, helpMessage, new String[]{"-i", "-o", "-c"});
ParallelExtraction e = new ParallelExtraction();
e.setImageList(new File(cmd.getProperty("-i")));
e.setOutFile(new File(cmd.getProperty("-o")));
String[] split = cmd.getProperty("-c").split(",");
for (int j = 0; j < split.length; j++) {
String className = split[j];
if (!className.contains(".")) {
className = "net.semanticmetadata.lire.imageanalysis.features.global." + className;
}
try {
e.addFeature((GlobalFeature) (Class.forName(className).newInstance()));
} catch (Exception erwin) {
erwin.printStackTrace();
}
}
if (!e.check()) {
printHelp();
System.exit(1);
}
e.run();
}
private boolean check() {
boolean result = true;
result = listOfFeatures.size() > 0 && imageList != null && outFile != null;
return result;
}
private static void printHelp() {
System.out.println(helpMessage);
}
public void setImageList(File imageList) {
this.imageList = imageList;
}
public void setOutFile(File outFile) {
this.outFile = outFile;
}
public void addFeature(GlobalFeature feature) {
listOfFeatures.add(feature);
}
@Override
public void run() {
System.out.printf("Starting to index files defined in %s.\n", imageList.getPath());
System.out.printf("Writing output to %s using the following features: \n", outFile.getPath());
listOfFeatures.forEach(globalFeature -> System.out.println(" - " + globalFeature.getFeatureName()));
System.out.println("------------------------------------------------------------");
try {
dos = new BufferedOutputStream(new FileOutputStream(outFile, false), 1024 * 1024 * 100);
StringBuilder sb = new StringBuilder("file;");
for (Iterator<GlobalFeature> iterator = listOfFeatures.iterator(); iterator.hasNext(); ) {
sb.append(iterator.next().getClass().getName() + ";");
}
sb.append("\n");
dos.write(sb.toString().getBytes());
dos.flush();
Producer p = new Producer(IOUtils.lineIterator(new FileReader(imageList)));
Thread pThread = new Thread(p);
pThread.start();
Monitoring m = new Monitoring();
Thread mThread = new Thread(m);
mThread.start();
LinkedList<Thread> consumerThreads = new LinkedList<>();
for (int i = 0; i < numOfThreads; i++) {
Consumer c = new Consumer();
Thread cThread = new Thread(c);
consumerThreads.add(cThread);
cThread.start();
}
pThread.join();
for (Iterator<Thread> iterator = consumerThreads.iterator(); iterator.hasNext(); ) {
iterator.next().join();
}
System.out.printf("Analyzed %d files\n", overallCount);
m.stopMonitoring();
dos.flush();
dos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void addFeatures(List features) {
for (Iterator<GlobalFeature> iterator = listOfFeatures.iterator(); iterator.hasNext(); ) {
GlobalFeature next = iterator.next();
try {
features.add(next.getClass().newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Producer implements Runnable {
private Iterator<String> imageFiles;
public Producer(Iterator<String> imageFiles) {
this.imageFiles = imageFiles;
overallCount = 0;
queue.clear();
}
public void run() {
File next;
String path;
while (imageFiles.hasNext()) {
path = imageFiles.next();
next = new File(path);
try {
byte[] buffer = IOUtils.readFully(new FileInputStream(next), (int) next.length());
queue.put(new WorkItem(path, buffer));
} catch (Exception e) {
System.err.println("Could not open " + path + ". " + e.getMessage());
}
}
path = null;
byte[] buffer = null;
for (int i = 0; i < numOfThreads * 3; i++) {
try {
queue.put(new WorkItem(path, buffer));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Monitoring implements Runnable {
private boolean isRunning;
public Monitoring() {
this.isRunning = true;
}
public void run() {
long end, gap = 1000 * monitoringInterval;
long start = System.currentTimeMillis();
try {
Thread.sleep(gap); // wait xx seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
while (isRunning) {
try {
// print the current status:
end = System.currentTimeMillis() - start;
System.out.printf("Analyzed %d images in %s ~ %3.2f ms each. (queue size is %d)\n", overallCount, StatsUtils.convertTime(end), ((overallCount > 0) ? ((float) end / (float) overallCount) : -1f), queue.size());
Thread.sleep(gap); // wait xx seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopMonitoring() {
this.isRunning = false;
}
}
class Consumer implements Runnable {
WorkItem tmp = null;
LinkedList<GlobalFeature> features = new LinkedList<GlobalFeature>();
int count = 0;
boolean locallyEnded = false;
Consumer() {
addFeatures(features);
}
public void run() {
while (!locallyEnded) {
try {
if (queue.size() == 0) Thread.sleep(75);
tmp = queue.take();
if (tmp.getBuffer() == null) {
locallyEnded = true;
} else {
try {
StringBuilder sb = new StringBuilder(256);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(tmp.getBuffer()));
sb.append(tmp.getFileName() + ";");
for (Iterator<GlobalFeature> iterator = features.iterator(); iterator.hasNext(); ) {
GlobalFeature next = iterator.next();
next.extract(img);
sb.append(org.apache.commons.codec.binary.Base64.encodeBase64String(next.getByteArrayRepresentation()) + ";");
}
sb.append("\n");
synchronized (dos) {
dos.write(sb.toString().getBytes());
overallCount++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
System.err.println("Error processing file " + tmp.getFileName());
e.printStackTrace();
}
}
}
}
}