001package org.openimaj.picslurper.output;
002
003import java.io.IOException;
004import java.io.PrintWriter;
005import java.net.URL;
006import java.util.ArrayList;
007import java.util.List;
008import java.util.Set;
009
010import org.apache.log4j.Logger;
011import org.kohsuke.args4j.Option;
012import org.kohsuke.args4j.ProxyOptionHandler;
013import org.openimaj.picslurper.client.TrendDetector;
014import org.openimaj.picslurper.client.TrendDetectorFeatureExtractor;
015import org.openimaj.util.pair.IndependentPair;
016
017import com.google.gson.Gson;
018import com.google.gson.GsonBuilder;
019
020/**
021 * Find trends using graphs for duplicate detection and graph cardinality for trend detection
022 *
023 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
024 *
025 */
026public class TrendDetectionOutputListener implements OutputListener {
027
028        private static final Logger logger = Logger.getLogger(TrendDetectionOutputListener.class);
029
030        private transient Gson gson = new GsonBuilder().setPrettyPrinting().create();
031
032        @Option(
033                        name = "--time-between-output",
034                        aliases = "-tbo",
035                        required = false,
036                        usage = "The time between trend outputs")
037        long timeToWait = 10000;
038
039        @Option(
040                        name = "--trend-output",
041                        aliases = "-to",
042                        required = false,
043                        usage = "Where to output trending images")
044        String trendOutput = "trends.json";
045
046        @Option(
047                        name = "--top-trends",
048                        aliases = "-ntrends",
049                        required = false,
050                        usage = "The number of trending sets to output")
051        int ntrends = 10;
052
053        @Option(
054                        name = "--feature-extractor-mode",
055                        aliases = "-feo",
056                        required = false,
057                        usage = "The feature extractor used by the trend detector",
058                        handler = ProxyOptionHandler.class,
059                        multiValued = true)
060        List<TrendDetectorFeatureMode> feMode = new ArrayList<TrendDetectorFeatureMode>();
061        List<TrendDetectorFeatureExtractor> feModeOp = new ArrayList<TrendDetectorFeatureExtractor>();
062
063        private long lastTrendOutput;
064        private List<IndependentPair<TrendDetectorFeatureMode, TrendDetector>> detectors;
065
066        /**
067         * Construct the publishing connector
068         */
069        public TrendDetectionOutputListener() {
070
071        }
072
073        @Override
074        public void newImageDownloaded(WriteableImageOutput written) {
075                try {
076                        for (IndependentPair<TrendDetectorFeatureMode, TrendDetector> detector : this.detectors) {
077                                detector.getSecondObject().indexImage(written);
078                        }
079                } catch (IOException e) {
080                        logger.error("Failed to index image!",e);
081                }
082                if(lastTrendOutput == -1 || lastTrendOutput + timeToWait < System.currentTimeMillis()){
083                        outputTrends();
084                        lastTrendOutput = System.currentTimeMillis();
085                }
086        }
087
088        @Override
089        public void failedURL(URL url, String reason) {
090
091        }
092
093        @Override
094        public void finished() {
095                outputTrends();
096        }
097        static class CountTrend{
098                long count;
099                Set<WriteableImageOutput> set;
100        }
101        private void outputTrends() {
102                for (IndependentPair<TrendDetectorFeatureMode, TrendDetector> detector : this.detectors) {
103                        List<Set<WriteableImageOutput>> trending = detector.getSecondObject().trending(ntrends);
104                        List<CountTrend> out = new ArrayList<CountTrend>();
105                        for (Set<WriteableImageOutput> set : trending) {
106                                logger.debug(String.format("[%d] %s", set.size(),set.toString()));
107                                CountTrend ct = new CountTrend();
108                                ct.count = set.size();
109                                ct.set = set;
110                                out.add(ct);
111                        }
112                        String output = gson.toJson(out);
113                        try {
114                                PrintWriter writer = new PrintWriter(trendOutput + "-" + detector.firstObject() + ".json","UTF-8");
115                                writer.println(output);
116                                writer.flush();
117                                writer.close();
118                        } catch (IOException e) {
119                                logger.error("Failed to write trends", e);
120                        }
121                }
122        }
123
124        @Override
125        public void prepare() {
126
127                detectors = new ArrayList<IndependentPair<TrendDetectorFeatureMode,TrendDetector>>();
128                TrendDetector detector;
129                for (int i = 0; i < this.feMode.size(); i++)
130                {
131                        TrendDetectorFeatureExtractor extractor = this.feModeOp.get(i);
132                        TrendDetectorFeatureMode mode = this.feMode.get(i);
133                        detector = new TrendDetector();
134                        detector.setFeatureExtractor(extractor);
135                        detectors.add(IndependentPair.pair(mode, detector));
136                }
137                lastTrendOutput = -1;
138        }
139
140}