package fr.unistra.pelican.algorithms.applied.video.shot;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.Image;
/**
* This class perform shot change detection using HSV block-based interframe
* differences in video sequences
*
* S. Lefèvre, N. Vincent, Efficient and Robust Shot Change Detection, Journal
* of Real Time Image Processing, Springer, Vol. 2, No. 1, october 2007, pages
* 23-34, doi:10.1007/s11554-007-0033-1.
*
* @author Sébatien Lefèvre
*/
public class AdaptiveShotChangeDetection extends Algorithm {
/**
* The input image sequence
*/
public Image input;
/**
* The threshold value used to locate shot change
*/
public double threshold;
/**
* The temporal inertia given to the difference measures
*/
public double inertia = 0.75;
/**
* The output result containing shot change positions
*/
public Integer[] output;
/**
* Default constructor
*/
public AdaptiveShotChangeDetection() {
super.inputs = "input";
super.options = "threshold,inertia";
super.outputs = "output";
}
/**
* Performs shot change detection using HSV block-based interframe
* differences in video sequences
*
* @param input
* The input image sequence
* @return The output result containing shot change positions
*/
public static Integer[] exec(Image input) {
return (Integer[]) new AdaptiveShotChangeDetection().process(input);
}
/**
* Performs shot change detection using HSV block-based interframe
* differences in video sequences
*
* @param input
* The input image sequence
* @param threshold
* The threshold value used to locate shot change
* @param inertia
* The temporal inertia given to the difference measures
* @return The output result containing shot change positions
*/
public static Integer[] exec(Image input, double threshold, double inertia) {
return (Integer[]) new AdaptiveShotChangeDetection().process(input,
threshold, inertia);
}
public static Integer[] exec(Image input, double threshold) {
return (Integer[]) new AdaptiveShotChangeDetection().process(input,
threshold);
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() {
// check if the image is a video sequence
if (input.tdim < 2)
throw new AlgorithmException(
"The input image is not a video sequence");
int duration = input.getTDim();
Integer tmp[] = new Integer[duration];
Double measures[] = new Double[duration];
Double thresholds[] = new Double[duration];
Double derivative[] = new Double[duration];
Double integral[] = new Double[duration];
// Compute HSV interframe difference
measures = HSVBasedInterframeDifference.exec(input);
// Compute threshold values
thresholds[0] = measures[0];
for (int t = 1; t < duration; t++)
thresholds[t] = inertia * thresholds[t - 1] + (1 - inertia)
* measures[t - 1];
// Compute derivative values
for (int t = 1; t < duration - 1; t++)
derivative[t - 1] = Math.abs(measures[t] - measures[t - 1]);
derivative[duration - 2] = 0.0;
derivative[duration - 1] = 0.0;
// Computer integral values
double sum = 0;
boolean integrate = false;
for (int t = 0; t < duration; t++) {
if (measures[t] > thresholds[t])
integrate = true;
else
integrate = false;
if (integrate)
sum += derivative[t];
else
sum = 0;
integral[t] = sum;
}
// Analyse the computed values
java.util.Arrays.fill(tmp, 0);
// Detect progressive transitions
for (int t = 0; t < duration; t++)
if (integral[t] > threshold) {
int t2 = t;
for (t2 = t; t2 >= 0 && integral[t2] > 0; t2--)
tmp[t2] = 1;
for (t2 = t; t2 < duration && integral[t2] > 0; t2++)
tmp[t2] = 1;
t = t2;
}
// Detect abrupt transitions
for (int t = 0; t < duration; t++)
if (derivative[t] > threshold) {
int t2 = t;
if (tmp[t] == 1 && tmp[t - 1] == 1)
for (t2 = t - 1; t2 >= 0 && tmp[t2] == 1; t2--)
tmp[t2] = 0;
if (tmp[t] == 1 && tmp[t + 1] == 1)
for (t2 = t + 1; t2 < duration && tmp[t2] == 1; t2++)
tmp[t2] = 0;
tmp[t] = 2;
}
output = tmp;
/*
* if (DEBUG) for (int t = 0; t < duration; t++) System.out.println(t +
* "\t" + measures[t] + "\t" + thresholds[t] + "\t" + derivative[t] +
* "\t" + integral[t] + "\t" + output[t]);
*/
}
}