package fr.unistra.pelican.demos.applied.video; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import fr.unistra.pelican.Image; import fr.unistra.pelican.PelicanException; import fr.unistra.pelican.algorithms.applied.video.shot.AdaptiveShotChangeDetection; import fr.unistra.pelican.algorithms.applied.video.shot.ClassicalShotChangeDetection; import fr.unistra.pelican.algorithms.geometric.BlockResampling2D; import fr.unistra.pelican.algorithms.io.PelicanImageLoad; import fr.unistra.pelican.algorithms.io.PelicanImageSave; import fr.unistra.pelican.algorithms.visualisation.Viewer2D; public class ShotChangeBenchmarkDemo { private static PrintStream out = null; private static boolean isReduced = true; private static String origin="/home/lefevre/data/global/video/jt1"; //private static String origin="/home/lefevre/data/global/video/foot1"; private static boolean ourBench=false; /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws PelicanException, FileNotFoundException { // Lancement du timer long t1=System.currentTimeMillis(); // Chargement String path=origin; //String path="/home/lefevre/data/global/video/foot3"; if (args.length!=0) path=args[0]; if(isReduced) path=path+"_reduced"; Image video = PelicanImageLoad.exec(path+".pelican"); if(origin.endsWith("jt1")) video=reduce(video,6000); File f = new File(path+".csv"); out = new PrintStream(new FileOutputStream(f)); boolean reduceOnly=false; if(reduceOnly) { video= BlockResampling2D.exec(video,8,8,false); PelicanImageSave.exec(video,path+"_reduced.pelican"); return; } // Affichage optionnel boolean viewOnly=false; if (viewOnly) { video.setColor(true); Viewer2D.exec(video,"Sequence"); } // Benchmark bench(video); // Fermeture du fichier out.close(); // Arrêt du timer long t2=System.currentTimeMillis()-t1; System.out.println("Démo terminée : "+ (t2/1000) + " secondes"); } public static void bench(Image video) throws PelicanException { // Gestion des paramètres double lthr, lthrS, lthrC, lthrT, lthrO; double hthr, hthrS, hthrC, hthrT, hthrO; int nthr, nthrS, nthrC, nthrT, nthrO; // thr : seuil fixe pour la comparaison avec la mesure dérivée lthr=0; hthr=20; nthr=6; // thrS : seuil de saturation pour considérer la teinte comme valable lthrS=0; hthrS=1; nthrS=6; // thrC : influence de la teinte et de la saturation lthrC=0; hthrC=1; nthrC=6; // thrT : inertie du seuil lthrT=0; hthrT=1; nthrT=6; // thrO : autres méthodes lthrO=0; hthrO=1; nthrO=1001; // Génération des différents paramètres double athr []=new double[nthr]; double athrS []=new double [nthrS]; double athrC []=new double [nthrC]; double athrT []=new double [nthrT]; double athrO []=new double [nthrO]; int thr, thrS, thrC, thrT, thrO; for (thr=0;thr<nthr;thr++) athr[thr]=lthr+thr*(hthr-lthr)/(nthr-1); for (thrS=0;thrS<nthrS;thrS++) athrS[thrS]=lthrS+thrS*(hthrS-lthrS)/(nthrS-1); for (thrC=0;thrC<nthrC;thrC++) athrC[thrC]=lthrC+thrC*(hthrC-lthrC)/(nthrC-1); for (thrT=0;thrT<nthrT;thrT++) athrT[thrT]=lthrT+thrT*(hthrT-lthrT)/(nthrT-1); for (thrO=0;thrO<nthrO;thrO++) athrO[thrO]=lthrO+thrO*(hthrO-lthrO)/(nthrO-1); // Lancement de la méthode avec les différents paramètres; Integer[] res=null; if (ourBench) for (thr=0;thr<nthr;thr++) for (thrS=0;thrS<nthrS;thrS++) for (thrC=0;thrC<nthrC;thrC++) for (thrT=0;thrT<nthrT;thrT++) { // Appel de la méthode res=null; System.gc(); res=(Integer[]) new AdaptiveShotChangeDetection().process(video,athr[thr],athrS[thrS],athrT[thrT],athrC[thrC],!isReduced); //res=AdaptiveShotChangeDetection.process(video,8,0.25,0.5,0.75,false); // Affichage des paramètres System.out.print("thr="+athr[thr]); System.out.print("\t thrS="+athrS[thrS]); System.out.print("\t thrC="+athrC[thrC]); System.out.print("\t thrT="+athrT[thrT]); System.out.println(""); out.print(athr[thr]+"\t"+athrS[thrS]+"\t"+athrC[thrC]+"\t"+athrT[thrT]+"\t"); // Affichage des résultats results(res); //System.out.println("Résultats terminés"); // Calcul des statistiques int delta=0; stats(res,delta); //System.out.println("Statistiques terminées"); } else for (thrO=0;thrO<nthrO;thrO++) { //double val=100*athrO[thrO]; //res=ClassicalShotChangeDetection.process(video,ClassicalShotChangeDetection.HISTO,val); double val=256*athrO[thrO]; res=ClassicalShotChangeDetection.exec(video,ClassicalShotChangeDetection.PIXEL,val); System.out.print("thrO="+val); System.out.println(""); out.print(val+"\t"); // Affichage des résultats results(res); //System.out.println("Résultats terminés"); // Calcul des statistiques int delta=0; stats(res,delta); //System.out.println("Statistiques terminées"); } } public static void stats(Integer [] res, int delta) { // Décompte du nombre de transitions int nbEffects=0; int nbCuts=0; int nb=0; for(int i=0;i<res.length-1;i++) { if(res[i]==1) { nbEffects++; while(res[i]==1 && i<res.length-1) i++; } if(res[i]==2) { nbCuts++; while(res[i]==2 && i<res.length-1) i++; } } nb=nbEffects+nbCuts; // Enregistrement des transitions int[][] data=new int[nb][3]; nb=0; for(int i=0;i<res.length-1;i++) { if(res[i]==1) { data[nb][0]=1; data[nb][1]=i+2; while(res[i]==1 && i<res.length-1) i++; data[nb][2]=i+1; nb++; } if(res[i]==2) { data[nb][0]=2; data[nb][1]=i+2; while(res[i]==2 && i<res.length-1) i++; data[nb][2]=i+1; nb++; } } // Chargement du résultat de référence int[][] ref=loadReference(); int refCuts=0; int refEffects=0; for(int i=0;i<ref.length;i++) { if (ref[i][0]==1) refEffects++; if (ref[i][0]==2) refCuts++; } // Comparaison itérative avec la référence boolean ref2 []=new boolean[ref.length]; boolean data2 []=new boolean[data.length]; boolean incrData,incrRef; int cptRef=0; int cptData=0; while (cptRef<ref.length && cptData<data.length) { int cases=0; boolean ok=false,ko=false; // Cas 1 : fin data < début ref => data < ref // Data XXXX // Ref XXXX if (data[cptData][2]+delta<ref[cptRef][1]) { cases++; ko=true; } // Cas 2 : fin data > début ref et fin data < fin ref => data <= ref // Data XXXXX // Ref XXXXX if (data[cptData][2]+delta>=ref[cptRef][1] && data[cptData][2]<=ref[cptRef][2]) { cases++; ok=true; data2[cptData]=true; ref2[cptRef]=true; } // Cas 3 : début data < début ref et fin data > fin ref => ref in data // Data XXXXXXXX // Ref XXXX if (data[cptData][1]<=ref[cptRef][1] && data[cptData][2]>=ref[cptRef][2]) { cases++; ok=true; data2[cptData]=true; ref2[cptRef]=true; } // Cas 4 : début data > début ref et fin data < fin ref => data in ref // Data XXXX // Ref XXXXXXXXX if (data[cptData][1]>=ref[cptRef][1] && data[cptData][2]<=ref[cptRef][2]) { cases++; ok=true; data2[cptData]=true; ref2[cptRef]=true; } // Cas 5 : début data > début ref et début data < fin ref => data >= ref // Data XXXXXX // Ref XXXXXXXX if (data[cptData][1]>=ref[cptRef][1] && data[cptData][1]<=ref[cptRef][2]+delta) { cases++; ok=true; data2[cptData]=true; ref2[cptRef]=true; } // Cas 6 : début data > fin ref => data > ref // Data XXXX // Ref XXXX if (data[cptData][1]>ref[cptRef][2]+delta) { ko=true; cases++; } // Vérification de l'unicité des cas if (cases==0) System.out.println("cases==0 : cptData="+cptData+" cptRef="+cptRef); if(ok && ko) System.out.println("ok && ko : cptData="+cptData+" cptRef="+cptRef); // Incrémentation des compteurs if (data[cptData][2]<=ref[cptRef][2]) incrData=true; else incrData=false; if (data[cptData][2]>=ref[cptRef][2]) incrRef=true; else incrRef=false; if (incrData) cptData++; if (incrRef) cptRef++; } // Calcul des mesures de qualité int fpEffects=0,fnEffects=0; int fpCuts=0,fnCuts=0; for (cptData=0;cptData<data2.length;cptData++) if (data2[cptData]==false) { if (data[cptData][0]==1) { fpEffects++; //System.out.println("Effet FP : "+data[cptData][1]+" à "+data[cptData][2]); } if (data[cptData][0]==2) { fpCuts++; //System.out.println("Cut FP : "+data[cptData][1]+" à "+data[cptData][2]); } } int fp=fpEffects+fpCuts; for (cptRef=0;cptRef<ref2.length;cptRef++) if (ref2[cptRef]==false) { if (ref[cptRef][0]==1) { fnEffects++; //System.out.println("Effet FN : "+ref[cptRef][1]+" à "+ref[cptRef][2]); } if (ref[cptRef][0]==2) { fnCuts++; //System.out.println("Cut FN : "+ref[cptRef][1]+" à "+ref[cptRef][2]); } } int fncEffects=refEffects-nbEffects+fpEffects; int fncCuts=refCuts-nbCuts+fpCuts; int fn=fnEffects+fnCuts; int fnc=fncEffects+fncCuts; // Affichage des statistiques System.out.print("Effects : "+"NB="+nbEffects+"\t FP="+fpEffects+"\t FN="+fnEffects+"\t FNC="+fncEffects); System.out.println("\t Recall="+(nbEffects)/((double)(nbEffects+fnEffects))+"\t Recall cor="+((nbEffects)/((double)(nbEffects+fncEffects)))+"\t Precision="+(nbEffects)/((double)(nbEffects+fpEffects))); System.out.print("Cuts : "+"NB="+nbCuts+"\t FP="+fpCuts+"\t FN="+fnCuts+"\t FNC="+fncCuts); System.out.println("\t Recall="+(nbCuts)/((double)(nbCuts+fnCuts))+"\t Recall cor="+((nbCuts)/((double)(nbCuts+fncCuts)))+"\t Precision="+(nbCuts)/((double)(nbCuts+fpCuts))); System.out.print("General : "+"NB="+nb+"\t FP="+fp+"\t FN="+fn+"\t FNC="+(refCuts+refEffects-nb+fp)); System.out.println("\t Recall="+(nb)/((double)(nb+fn))+"\t Recall cor="+((nb)/((double)(nb+fnc)))+"\t Precision="+(nb)/((double)(nb+fp))); out.print("\t"+nbEffects+"\t"+fpEffects+"\t"+fnEffects+"\t"+(refEffects-nbEffects+fpEffects)); out.print("\t"+(nbEffects)/((double)(nbEffects+fnEffects))+"\t"+((nbEffects)/((double)(refEffects+fpEffects)))+"\t"+(nbEffects)/((double)(nbEffects+fpEffects))); out.print("\t"+nbCuts+"\t"+fpCuts+"\t"+fnCuts+"\t"+(refCuts-nbCuts+fpCuts)); out.print("\t"+(nbCuts)/((double)(nbCuts+fnCuts))+"\t"+((nbCuts)/((double)(refCuts+fpCuts)))+"\t"+(nbCuts)/((double)(nbCuts+fpCuts))); out.print("\t"+nb+"\t"+fp+"\t"+fn+"\t"+(refCuts+refEffects-nb+fp)); out.print("\t"+(nb)/((double)(nb+fn))+"\t"+((nb)/((double)(refCuts+refEffects+fp)))+"\t"+(nb)/((double)(nb+fp))); out.println(); } public static void results(Integer [] res) { // Affichage des résultats for(int i=0;i<res.length-1;i++) { if(res[i]==1) { //System.out.print("Effet : "+(i+2)); while(res[i]==1 && i<res.length-1) i++; //System.out.println(" à "+(i+1)); } if(res[i]==2) { //System.out.print("Cut : "+(i+2)); while(res[i]==2 && i<res.length-1) i++; //System.out.println(" à "+(i+1)); } } } public static int[][] loadReference() { int [][] ref=null; int cptRef=0; String file=origin+"-ref.txt"; String line=""; try { // Lecture du fichier BufferedReader f = new BufferedReader(new FileReader(file)); // Nombre de transitions line=f.readLine(); int nb=Integer.parseInt(line); ref=new int[nb][3]; // Parcours des transitions line=f.readLine(); while (line!=null) { // Détermination du type de transition if (line.charAt(0)=='E') ref[cptRef][0]=1; if (line.charAt(0)=='C') ref[cptRef][0]=2; if (line.charAt(0)=='/') { line=f.readLine(); continue; } // Détermination des frontières de la transition ref[cptRef][1]=Integer.parseInt(line.substring(line.indexOf(':')+1,line.indexOf('-'))); ref[cptRef][2]=Integer.parseInt(line.substring(line.lastIndexOf('-')+1)); //System.out.println(ref[cptRef][0]+":"+ref[cptRef][1]+" à "+ref[cptRef][2]+" => "+line); cptRef++; line=f.readLine(); } f.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return ref; } /* public static int[][] loadResults() { int [][] ref=null; int cptRef=0; String file=origin; if (isReduced) file=file+"_reduced"; file=file+".csv"; String line=""; try { // Nombre de résultats BufferedReader f = new BufferedReader(new FileReader(file)); line=f.readLine(); while (line!=null) { cptRef++; line=f.readLine(); } int nb=cptRef; f.close(); f = new BufferedReader(new FileReader(file)); // Lecture du fichier line=f.readLine(); int largeur=30; ref=new int[nb][largeur]; cptRef=0; while (line!=null) { int indice1=0; int indice2=line.indexOf('\t'); ref[cptRef][i]=Integer.parseInt(line.substring(0,indice)); for(i=1;i<largeur;i++) { indice1=indice2+1; indice2=line.indexOf('\t',indice1); ref[cptRef][i]=Integer.parseInt(line.substring(indice1,indice2)); // Détermination des frontières de la transition ref[cptRef][1]=Integer.parseInt(line.substring(line.indexOf(':')+1,line.indexOf('-'))); ref[cptRef][2]=Integer.parseInt(line.substring(line.lastIndexOf('-')+1)); //System.out.println(ref[cptRef][0]+":"+ref[cptRef][1]+" à "+ref[cptRef][2]+" => "+line); cptRef++; line=f.readLine(); } f.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return ref; } */ public static Image reduce(Image im, int size) { Image result=im.newInstance(im.getXDim(),im.getYDim(),im.getZDim(),size,im.getBDim()); for(int t=0;t<size;t++) for(int x=0;x<im.getXDim();x++) for(int y=0;y<im.getYDim();y++) for(int z=0;z<im.getZDim();z++) for(int b=0;b<im.getBDim();b++) result.setPixelByte(x,y,z,t,b,im.getPixelByte(x,y,z,t,b)); return result; } }