package fr.unistra.pelican.algorithms.applied.video.shot; import fr.unistra.pelican.Algorithm; import fr.unistra.pelican.AlgorithmException; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.conversion.RGBToHSV; import fr.unistra.pelican.algorithms.geometric.BlockResampling2D; /** * This class computes HSV block-based interframe differences in image sequences * for shot change detection * * 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 HSVBasedInterframeDifference extends Algorithm { /** * The input image sequence */ public Image input; /** * The saturation threshold, hue values are not considered when saturation * is below */ public double saturationThr = 0.25; /** * The weight of hue versus saturation */ public double hueWeight = 0.5; /** * The subsampling level used to analyse the image sequence */ public int subsampling = 8; /** * The array of difference values */ public Double[] output; /** * Default constructor */ public HSVBasedInterframeDifference() { super.inputs = "input"; super.options = "saturationThr,hueWeight,subsampling"; super.outputs = "output"; } /** * Computes HSV block-based interframe differences in image sequences for * shot change detection * * @param input * The input image sequence * @return The array of difference values */ public static Double[] exec(Image input) { return (Double[]) new HSVBasedInterframeDifference().process(input); } /** * Computes HSV block-based interframe differences in image sequences for * shot change detection * * @param input * The input image sequence * @param saturationThr * The saturation threshold * @param hueWeight * The weight of hue versus saturation * @param subsampling * The subsampling level used to analyse the image sequence * @return The array of difference values */ public static Double[] exec(Image input, double saturationThr, double hueWeight, int subsampling) { return (Double[]) new HSVBasedInterframeDifference().process(input, saturationThr, hueWeight, subsampling); } /* * (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(); output = new Double[duration]; Image img1; Image img2; double alpha; double diff; double hue, sat; double sat1, sat2; double sum; // Sequence scanning for (int t = 1; t < duration; t++) { img1 = input.getImage4D(t - 1, Image.T);// getColorByteChannelZT(0,t-1); img2 = input.getImage4D(t, Image.T);// getColorByteChannelZT(0,t); if (subsampling > 1) { img1 = (Image) new BlockResampling2D().process(img1, subsampling, subsampling,false); img2 = (Image) new BlockResampling2D().process(img2, subsampling, subsampling,false); } if (input.isColor()) { img1 = (Image) new RGBToHSV().process(img1); img2 = (Image) new RGBToHSV().process(img2); } sum = 0; for (int x = 0; x < img1.getXDim(); x++) for (int y = 0; y < img1.getYDim(); y++) { // Compute the hue difference hue = (img1.getPixelXYBDouble(x, y, 2) - img2.getPixelXYBDouble(x, y, 2) + 1) % 1; if (hue > 0.5) hue = 1 - hue; hue *= 2; // Compute the sat difference sat1 = img1.getPixelXYBDouble(x, y, 1); sat2 = img2.getPixelXYBDouble(x, y, 1); sat = Math.abs(sat1 - sat2); // Test the sat level to compute weights if (sat1 > saturationThr && sat2 > saturationThr) alpha = hueWeight; else alpha = 0; // Difference between the two pixels diff = alpha * hue + (1 - alpha) * sat; sum += diff; } sum /= (img1.getXDim() * img1.getYDim()); output[t - 1] = sum * 100; } output[duration - 1] = 0.0; } }