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 org.bytedeco.javacpp.opencv_nonfree;
import java.util.*;
import static resa.evaluation.topology.tomVLD.Constants.*;
import static resa.evaluation.topology.tomVLD.StormConfigManager.getInt;
import static resa.evaluation.topology.tomVLD.StormConfigManager.getListOfStrings;
/**
* Created by Intern04 on 5/8/2014.
*/
public class PatchProcessorBoltMultipleEcho extends BaseRichBolt {
OutputCollector collector;
opencv_nonfree.SIFT sift;
/** Instance of detector */
private List<StormVideoLogoDetectorGamma> detectors;
/** This counts from which patches the update has been already received */
//private HashSet<Serializable.PatchIdentifier> receivedUpdatesFrom;
//Modified by Tom on Sep 8, 2014
private Map<Serializable.PatchIdentifier, Boolean> receivedUpdatesFrom;
private static int MaxSizeOfReceivedUpdatesFrom = 4096;
/** The receipt */
private HashMap<Integer, Serializable.Mat> frameMap;
private HashMap< Integer, Queue<Serializable.PatchIdentifier> > patchQueue;
private HashMap< Integer, Queue<LogoTemplateUpdateBeta> > templateQueue;
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
int minNumberOfMatches = Math.min(getInt(map, "minNumberOfMatches"), 4);
this.collector = outputCollector;
// TODO: get path to logos & parameters from config
Parameters parameters = new Parameters()
.withMatchingParameters(
new Parameters.MatchingParameters()
.withMinimalNumberOfMatches(minNumberOfMatches)
);
sift = new opencv_nonfree.SIFT(0, 3, parameters.getSiftParameters().getContrastThreshold(),
parameters.getSiftParameters().getEdgeThreshold(), parameters.getSiftParameters().getSigma());
List<String> templateFiles = getListOfStrings(map, "originalTemplateFileNames");
int maxAdditionTemp = ConfigUtil.getInt(map, "maxAdditionTemp", 4);
detectors = new ArrayList<>();
for (int logoIndex = 0; logoIndex < templateFiles.size(); logoIndex ++) {
detectors.add(new StormVideoLogoDetectorGamma(parameters, templateFiles.get(logoIndex), logoIndex, maxAdditionTemp));
}
//Modified by Tom on Sep 8, 2014
receivedUpdatesFrom = new LinkedHashMap<Serializable.PatchIdentifier, Boolean>(){
@Override
protected boolean removeEldestEntry(Map.Entry<Serializable.PatchIdentifier, Boolean> eldest) {
return size() > MaxSizeOfReceivedUpdatesFrom;
}
};
frameMap = new HashMap<>();
patchQueue = new HashMap<>();
templateQueue = new HashMap<>();
}
@Override
public void execute(Tuple tuple) {
String streamId = tuple.getSourceStreamId();
if (streamId.equals(SAMPLE_FRAME_STREAM))
processFrame(tuple);
else if (streamId.equals(PATCH_STREAM))
processPatch(tuple);
else if (streamId.equals(LOGO_TEMPLATE_UPDATE_STREAM))
processNewTemplate(tuple);
else if (streamId.equals(CACHE_CLEAR_STREAM))
processCacheClear(tuple);
collector.ack(tuple);
}
// Fields("frameId", "frameMat", "patchCount"));
private void processFrame( Tuple tuple ) {
int frameId = tuple.getIntegerByField(FIELD_FRAME_ID);
int sampleID = tuple.getIntegerByField(FIELD_SAMPLE_ID);
Serializable.Mat mat = (Serializable.Mat) tuple.getValueByField(FIELD_FRAME_MAT);
int patchCount = tuple.getIntegerByField(FIELD_PATCH_COUNT);
if (frameMap.containsKey(frameId)) {
if (Debug.topologyDebugOutput)
System.err.println(this.getClass() + "#" + "processFrame(): Received duplicate frame");
} else {
frameMap.put(frameId, mat);
}
if (patchQueue.containsKey(frameId)) {
Queue<Serializable.PatchIdentifier> queue = patchQueue.get(frameId);
while (!queue.isEmpty()) {
Serializable.PatchIdentifier hostPatch = queue.poll();
List<Serializable.Rect> detectedLogoList = new ArrayList<>();
SIFTfeatures sifTfeatures = new SIFTfeatures(sift, mat.toJavaCVMat(), hostPatch.roi.toJavaCVRect(), true);
for (int logoIndex = 0; logoIndex < detectors.size(); logoIndex ++) {
StormVideoLogoDetectorGamma detector = detectors.get(logoIndex);
//detector.detectLogosInRoi(mat.toJavaCVMat(), hostPatch.roi.toJavaCVRect());
detector.detectLogosByFeatures(sifTfeatures);
Serializable.Rect detectedLogo = detector.getFoundRect();
if (detectedLogo != null) {
collector.emit(LOGO_TEMPLATE_UPDATE_STREAM, new Values(hostPatch, detectedLogo, detector.getParentIdentifier(), logoIndex));
}
detectedLogoList.add(detectedLogo);
}
collector.emit(DETECTED_LOGO_STREAM, tuple, new Values(frameId, hostPatch, detectedLogoList, patchCount, sampleID));
}
} else {
//patchQueue.put(frameId, new LinkedList<>());
}
if (templateQueue.containsKey(frameId)) {
Queue<LogoTemplateUpdateBeta> queue = templateQueue.get(frameId);
while (!queue.isEmpty()) {
LogoTemplateUpdateBeta update = queue.poll();
Serializable.Rect roi = update.detectedLogoRect;
Serializable.PatchIdentifier hostPatchIdentifier = update.hostPatchIdentifier;
Serializable.PatchIdentifier parent = update.parentIdentifier;
int logoIndex = update.logoIndex;
///detector.addTemplateByRect(hostPatchIdentifier, mat, roi);
///detector.incrementPriority(parent, 1);
detectors.get(logoIndex).addTemplateByRect(hostPatchIdentifier, mat, roi);
detectors.get(logoIndex).incrementPriority(parent, 1);
}
} else {
//templateQueue.put(frameId, new LinkedList<>());
}
}
// Fields("patchIdentifier", "patchCount"));
private void processPatch( Tuple tuple ) {
Serializable.PatchIdentifier patchIdentifier = (Serializable.PatchIdentifier) tuple.getValueByField(FIELD_PATCH_IDENTIFIER);
int patchCount = tuple.getIntegerByField(FIELD_PATCH_COUNT);
int frameId = patchIdentifier.frameId;
int sampleID = tuple.getIntegerByField(FIELD_SAMPLE_ID);
if (frameMap.containsKey(frameId)) {
List<Serializable.Rect> detectedLogoList = new ArrayList<>();
SIFTfeatures sifTfeatures = new SIFTfeatures(sift, frameMap.get(frameId).toJavaCVMat(), patchIdentifier.roi.toJavaCVRect(), true);
for (int logoIndex = 0; logoIndex < detectors.size(); logoIndex ++) {
StormVideoLogoDetectorGamma detector = detectors.get(logoIndex);
//detector.detectLogosInRoi(frameMap.get(frameId).toJavaCVMat(), patchIdentifier.roi.toJavaCVRect());
detector.detectLogosByFeatures(sifTfeatures);
Serializable.Rect detectedLogo = detector.getFoundRect();
if (detectedLogo != null) {
collector.emit(LOGO_TEMPLATE_UPDATE_STREAM, new Values(patchIdentifier, detectedLogo, detector.getParentIdentifier(), logoIndex));
}
detectedLogoList.add(detectedLogo);
}
collector.emit(DETECTED_LOGO_STREAM, tuple,
new Values(frameId, patchIdentifier, detectedLogoList, patchCount, sampleID));
} else {
if (!patchQueue.containsKey(frameId))
patchQueue.put(frameId, new LinkedList<>());
patchQueue.get(frameId).add(patchIdentifier);
}
}
// Fields("hostPatchIdentifier", "detectedLogoRect", "parentIdentifier"));
private void processNewTemplate(Tuple tuple) {
Serializable.PatchIdentifier receivedPatchIdentifier = (Serializable.PatchIdentifier)tuple.getValueByField(FIELD_HOST_PATCH_IDENTIFIER);
// TODO: This container could become very large, need to clear it after some time
// Modified by Tom, use LinkedHashMap for receivedUpdatesFrom, it will automatically remove the oldest
// element when its size beyond some threshold.
if ( !receivedUpdatesFrom.containsKey(receivedPatchIdentifier) ) {
receivedUpdatesFrom.put(receivedPatchIdentifier, Boolean.TRUE);
Serializable.Rect roi = (Serializable.Rect) tuple.getValueByField(FIELD_DETECTED_LOGO_RECT);
Serializable.PatchIdentifier parent = (Serializable.PatchIdentifier) tuple.getValueByField(FIELD_PARENT_PATCH_IDENTIFIER);
int logoIndex = tuple.getIntegerByField(FIELD_LOGO_INDEX);
int frameId = receivedPatchIdentifier.frameId;
if (frameMap.containsKey(frameId)) {
Serializable.Mat mat = frameMap.get(frameId);
detectors.get(logoIndex).addTemplateByRect(receivedPatchIdentifier, mat, roi);
detectors.get(logoIndex).incrementPriority(parent, 1);
} else {
if (!templateQueue.containsKey(frameId))
templateQueue.put(frameId, new LinkedList<>());
templateQueue.get(frameId).add(new LogoTemplateUpdateBeta(receivedPatchIdentifier, roi, parent, logoIndex));
}
} else {
if (Debug.topologyDebugOutput)
System.out.println("PatchProcessorBolt: Received duplicate message");
}
}
// Fields("frameId")
private void processCacheClear(Tuple tuple) {
int frameId = tuple.getIntegerByField(FIELD_FRAME_ID);
frameMap.remove(frameId);
patchQueue.remove(frameId);
templateQueue.remove(frameId);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declareStream(DETECTED_LOGO_STREAM,
new Fields(FIELD_FRAME_ID, FIELD_PATCH_IDENTIFIER, FIELD_FOUND_RECT, FIELD_PATCH_COUNT, FIELD_SAMPLE_ID));
outputFieldsDeclarer.declareStream(LOGO_TEMPLATE_UPDATE_STREAM,
new Fields(FIELD_HOST_PATCH_IDENTIFIER, FIELD_DETECTED_LOGO_RECT, FIELD_PARENT_PATCH_IDENTIFIER, FIELD_LOGO_INDEX));
}
}