package resa.evaluation.topology.tomVLD;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static resa.evaluation.topology.tomVLD.Constants.*;
/**
* Created by Tom Fu at Mar 24, 2015
* This bolt is designed to collect the found rects from the Patch Process bolt,
* When all the found rect message (the found rect data can be null) is received (#messages == patch_count)
* It sends out the foundRectList to the patchDraw bolt
* when sampleFrame (denoted by N) > 1, actually, only the Nth frame will be processed (and also generate related patches)
* while the other frames will be just input and draw the founded rects, generated by the nearest Nth frame
* (which means, the rects generated at the Nth frame, will last for N )
*
* Updated on April 29, the way to handle frame sampling issue is changed, this is pre-processed by the spout not to
* send out unsampled frames to the patch generation bolt.
*/
public class PatchAggFox extends BaseRichBolt {
OutputCollector collector;
/* Keeps track on which patches of the certain frame have already been received */
//Map< Integer, HashSet<Serializable.Rect> > frameAccount;
Map< Integer, Integer> frameMonitor;
/* Contains the list of logos found found on a given frame */
Map< Integer, List<List<Serializable.Rect>> > foundRectAccount;
private int sampleFrames;
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.collector = outputCollector;
frameMonitor = new HashMap<>();
foundRectAccount = new HashMap<>();
sampleFrames = ConfigUtil.getInt(map, "sampleFrames", 1);
}
@Override
public void execute(Tuple tuple) {
//opencv_core.IplImage fk = new opencv_core.IplImage();
int frameId = tuple.getIntegerByField(FIELD_FRAME_ID);
int patchCount = tuple.getIntegerByField(FIELD_PATCH_COUNT);
List<Serializable.Rect> foundRect = (List<Serializable.Rect>)tuple.getValueByField(FIELD_FOUND_RECT);
if (!foundRectAccount.containsKey(frameId)){
foundRectAccount.put(frameId, new ArrayList<>());
for (int logoIndex = 0; logoIndex < foundRect.size(); logoIndex ++) {
foundRectAccount.get(frameId).add(new ArrayList<>());
}
}
/* Updating the list of detected logos on the frame */
for (int logoIndex = 0; logoIndex < foundRect.size(); logoIndex ++) {
if (foundRect.get(logoIndex) != null) {
foundRectAccount.get(frameId).get(logoIndex).add(foundRect.get(logoIndex));
}
}
frameMonitor.computeIfAbsent(frameId, k->0);
frameMonitor.computeIfPresent(frameId, (k,v)->v+1);;
/* If all patches of this frame are collected proceed to the frame aggregator */
if (frameMonitor.get(frameId) == patchCount) {
if (frameId % sampleFrames == 0) {
for (int f = frameId; f < frameId + sampleFrames; f ++){
collector.emit(PROCESSED_FRAME_STREAM, new Values(f, foundRectAccount.get(frameId)));
}
} else {//shall not be here!
throw new IllegalArgumentException("frameId % sampleFrames != 0, frameID: " + frameId + ", sampleFrames: " + sampleFrames);
}
frameMonitor.remove(frameId);
foundRectAccount.remove(frameId);
}
collector.ack(tuple);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declareStream(PROCESSED_FRAME_STREAM, new Fields(FIELD_FRAME_ID, FIELD_FOUND_RECT_LIST));
}
}