import java.util.*;
/**
* This class represents a segmentation related to a video file
* used in shot boundary detection task programs of TREC 2001.
*
* @author
* This software was produced by NIST, an agency of the
* U.S. government, and by statute is not subject to copyright in the
* United States. Recipients of this software assume all
* responsibilities associated with its operation, modification and
* maintenance.
*
*/
public class Segmentation{
/**
* The video name the segmentation is related to.
*
* @see #getVideoName()
*/
private String videoName;
/**
* This object is containing all the transitions of the segmentation.
*
* @see #getElements()
*/
private TreeSet transitionSet;
private Vector dropped;
/**
* The number of frames of the video.
*
* @see #getElements()
*/
private int totalFrameNumber = 0;
/**
* Constructs Segmentation object with an ordering comparator for its set of transitions
*
* @param videoName The video name the segmentation is related to.
* @param orderingComparator The comparator used to order transitions in the set of transitions
*/
public Segmentation(String videoName, Comparator orderingComparator){
this(videoName, orderingComparator, 0);
//this.videoName = videoName;
//this.transitionSet = new TreeSet(orderingComparator);
//this.dropped = new Vector();
}
/**
* Constructs Segmentation object with an ordering comparator for
* its set of transitions.
*
* @param videoName The video name the segmentation is related to.
* @param orderingComparator The comparator used to order transitions in the set of trnasitions.
* @param totalFrameNumber The number of frames of the video.
*/
public Segmentation(String videoName, Comparator orderingComparator, int totalFrameNumber){
this.totalFrameNumber = totalFrameNumber;
this.videoName = videoName;
this.transitionSet = new TreeSet(orderingComparator);
this.dropped = new Vector();
}
/**
* Process the comparison between the current assumed reference
* segmentation and the given system segmentation.
*
* @param sysId The system Id of the given system segmentation.
* @param systemSegmentation The system segmentation to be compared with.
* @param shortGradualThreshold The threshold below which short gradual
* transition can match an abrupt tansition.
* @return an object representing all the results (measures...) of the comparison.
* @exception TransitionDefinitionException if the definition of a
* transition is not correct (pre-frame >= post-frame).
*/
public comparisonResult processComparison(String sysId,
Segmentation systemSegmentation
) throws TransitionDefinitionException{
//**********************************unchanged
comparisonResult result = new comparisonResult(sysId, this.videoName,
this.totalFrameNumber);
int insertedTransCount = 0;
int deletedTransCount = 0;
int insertedTransCountCut = 0;
int deletedTransCountCut = 0;
int insertedTransCountGradual = 0;
int deletedTransCountGradual = 0;
int frameNumCount = 0;
int frameRecallDenCount = 0;
int framePrecisionDenCount = 0;
String nl = System.getProperty("line.separator");
String insertionsSection = nl+""+nl+nl;
String cutMatchSection = nl;
String gradualMatchSection = nl;
String deletionsSection = nl+""+nl+nl;
//*********************************** unchanged
// For each transition within the Reference Segmentation (this)
// detection of insertion or match.
// 1-Ensure that the transition are in time sequence
// ensured only if the comparator for the TreeSet is the appropriate one
// 2-Verify that cut are considered as 2 frames transition before overlapping test !!!!!!!!!!
// verified cause as is: cut overlappings are enabled cause of ref-cut expansion
Iterator referenceIterator = this.transitionSet.iterator();
while(referenceIterator.hasNext()){
Transition aReferenceTransition = (Transition) referenceIterator.next();
// Expanding the reference transition
if(aReferenceTransition.isCut()){
if(aReferenceTransition.getPre() < 5)
aReferenceTransition.reset(0, aReferenceTransition.getPost() + 5);
else
aReferenceTransition.reset(aReferenceTransition.getPre() - 5, aReferenceTransition.getPost() + 5);
}
Iterator systemIterator = systemSegmentation.getElements();
Transition bestMatch = null;
double bestMatchFrameRecall = 0.0;
double bestMatchFramePrecision = 0.0;
int bestOverlap = 0;
while(systemIterator.hasNext()){
Transition aSystemTransition = (Transition) systemIterator.next();
// Expanding the systemTransition if it is a CUT
// dont forget to reset it to normal values after the loop
if(aSystemTransition.isCut()){
if(aSystemTransition.getPre() == 0){
aSystemTransition.reset(0, aSystemTransition.getPost() + 1);
}
else
aSystemTransition.reset(aSystemTransition.getPre() - 1, aSystemTransition.getPost() + 1);
}
Transition intersection = null;
if(aSystemTransition.matched == false &&
(intersection = aSystemTransition.intersection(aReferenceTransition)) != null &&
aSystemTransition.sameType(aReferenceTransition)){
int intersectionLength = intersection.length();
if(intersectionLength > bestOverlap){
//Re-init previous bestMatch matched value
if(bestMatch != null)
bestMatch.matched = false;
bestMatch = aSystemTransition;
aSystemTransition.matched = true;
aReferenceTransition.matched = true;
bestOverlap = intersectionLength;
bestMatchFrameRecall = (double) bestOverlap / (double) aReferenceTransition.length();
bestMatchFramePrecision = (double) bestOverlap / (double) bestMatch.length();
}
else if(intersectionLength > 0 && intersectionLength == bestOverlap){
double candidateFramePrecision = (double) intersectionLength / (double) aSystemTransition.length();
if(candidateFramePrecision > bestMatchFramePrecision){
//Re-init previous bestMatch matched value
if(bestMatch != null)
bestMatch.matched = false;
bestMatch = aSystemTransition;
aSystemTransition.matched = true;
aReferenceTransition.matched = true;
bestOverlap = intersection.length();
}
//if still equal : you arrived after so nothing
}
}
// Reseting the system transition size
// if it is a CUT (previously expanded)
if(aSystemTransition.isCut()){
if(aSystemTransition.getPre() == 0){
aSystemTransition.reset(aSystemTransition.getPost() - 2, aSystemTransition.getPost() - 1);
}
else aSystemTransition.reset(aSystemTransition.getPre() + 1, aSystemTransition.getPost() - 1);
}
}//End LOOP over system transitions
// Reseting the reference transition size
// if it is a CUT (previously expanded)
if(aReferenceTransition.isCut()){
if(aReferenceTransition.getPre() == 0)
aReferenceTransition.reset(aReferenceTransition.getPost() - 6, aReferenceTransition.getPost() - 5);
else
aReferenceTransition.reset(aReferenceTransition.getPre() + 5, aReferenceTransition.getPost() - 5);
}
// Persistance for aReferenceTransition
// either deletion or match
if(!aReferenceTransition.matched){
deletionsSection += aReferenceTransition.refToString();
deletedTransCount++;
if(aReferenceTransition.isCut() || aReferenceTransition.isShortGradual())
deletedTransCountCut++;
else
deletedTransCountGradual++;
}
else{
if((aReferenceTransition.isCut() && bestMatch.isCut()) ||
(aReferenceTransition.isCut() && bestMatch.isShortGradual()) ||
(aReferenceTransition.isShortGradual() && bestMatch.isCut()) ||
(aReferenceTransition.isShortGradual() && bestMatch.isShortGradual())){
cutMatchSection += nl + "" + nl + aReferenceTransition.refToString() +
bestMatch.sysToString() +"";
}
else{
frameNumCount += bestMatch.intersection(aReferenceTransition).length();
frameRecallDenCount += aReferenceTransition.length();
framePrecisionDenCount += bestMatch.length();
gradualMatchSection += nl + "" + nl +
aReferenceTransition.refToString() +
bestMatch.sysToString() +
"";
}
}
// RE INIT matching info
aReferenceTransition.matched = false;
}
// Enumeration of system transitions to fill in the insertion section
Iterator systemIterator = systemSegmentation.getElements();
while(systemIterator.hasNext()){
Transition aSystemTransition = (Transition) systemIterator.next();
if(!aSystemTransition.matched){
insertionsSection += aSystemTransition.sysToString();
insertedTransCount++;
if(aSystemTransition.isCut() || aSystemTransition.isShortGradual()) insertedTransCountCut++;
else insertedTransCountGradual++;
}
}
insertionsSection += nl+""+nl;
deletionsSection += nl+""+nl;
result.setResults(systemSegmentation.droppedToString(),
this.getTransitionCount(),
insertedTransCount,
deletedTransCount,
cutMatchSection,
this.getCutCount(),
insertedTransCountCut,
deletedTransCountCut,
gradualMatchSection,
insertedTransCountGradual,
deletedTransCountGradual,
frameNumCount,
frameRecallDenCount,
framePrecisionDenCount,
insertionsSection,
deletionsSection);
return result;
}
/**
* Returns the number of Cut transitions within the segmentation.
*
* @return the number of Cut transitions within the segmentation.
*/
public int getCutCount(){
int toReturn = 0;
Iterator i = this.transitionSet.iterator();
while(i.hasNext()){
Transition t = (Transition) i.next();
if(t.isCut() || t.isShortGradual()) toReturn++;
}
return toReturn;
}
/**
* Returns an iterator on the transitions within the segmentation.
*
* @return an iterator on the transitions within the segmentation.
*/
public Iterator getElements(){
return this.transitionSet.iterator();
}
/**
* Add a given transition to the segmentation.
*
* @param aTransition the transition to be added to the segmentation.
*/
public void add(Transition aTransition){
boolean foundInDropped = false;
Enumeration enumDropped = this.dropped.elements();
while(enumDropped.hasMoreElements() && !foundInDropped){
Transition t = (Transition) enumDropped.nextElement();
if(t.intersection(aTransition) != null)
foundInDropped = true;
}
if(!transitionSet.contains(aTransition) && !foundInDropped){
transitionSet.add(aTransition);
}
else{
this.dropped.add(aTransition);
//On the way to find the removed transition that intersects
//Only justification to keep TreeSet structure is for the ordering in iteration
//in processing comparison so in order to get ordered output files
//Again: iteration over the treeSet ! after the ones in contains() and add() !!
Transition movedToDropped = null;
Iterator setIterator = this.transitionSet.iterator();boolean found = false;
while(setIterator.hasNext() && !found){
Transition t = (Transition) setIterator.next();
if(t.intersection(aTransition) != null){
movedToDropped = t;
found = true;
}
}
if(movedToDropped != null){ this.dropped.add(movedToDropped);}
this.transitionSet.remove(aTransition);
}
}
/**
* Returns the video name the segmentation is related to.
*
* @return the video name the segmentation is related to.
*/
public String getVideoName(){
return videoName;
}
/**
* Returns the number of transitions within the segmentation.
*
* @return the number of transitions within the segmentation.
*/
public int getTransitionCount(){
return transitionSet.size();
}
public int getDroppedCount(){
return this.dropped.size();
}
public String droppedToString(){
String nl = System.getProperty("line.separator");
StringBuffer toReturn = new StringBuffer();
Enumeration enumDropped = this.dropped.elements();
while(enumDropped.hasMoreElements()){
Transition s = (Transition) enumDropped.nextElement();
toReturn.append(s.toString("droppedTrans"));
}
return toReturn.toString();
}
/**
* Returns an Xml string representing the segmentation in a pre-defined format.
*
* @return an Xml string representing the segmentation.
*/
public String toString(){
String toReturn = ""+System.getProperty("line.separator");
Iterator e = transitionSet.iterator();
while(e.hasNext()){
Transition s = (Transition) e.next();
toReturn += s.toString();
}
toReturn += ""+System.getProperty("line.separator");
return toReturn;
}
}//END CLASS