package fr.unistra.pelican.algorithms.statistics;
import fr.unistra.pelican.Algorithm;
import fr.unistra.pelican.AlgorithmException;
import fr.unistra.pelican.Image;
import fr.unistra.pelican.algorithms.logical.AND;
import fr.unistra.pelican.algorithms.logical.BinaryDifference;
import fr.unistra.pelican.algorithms.logical.CompareImage;
import fr.unistra.pelican.algorithms.logical.OR;
import fr.unistra.pelican.algorithms.morphology.binary.geodesic.FastBinaryReconstruction;
import fr.unistra.pelican.algorithms.segmentation.flatzones.BooleanConnectedComponentsLabeling;
/**
* This class computes some quality measures (pixel-based, region-based, and
* mixed) between a binary detection result and a reference image, the results
* are gathered into an output string
*
* @author Lefevre
*/
public class DetectionQualityEvaluation extends Algorithm {
/**
* The first image
*/
public Image input;
/**
* The second image
*/
public Image reference;
/**
* A flag to include pixel-based evaluation
*/
public boolean pixel = true;
/**
* A flag to include region-based evaluation
*/
public boolean region = true;
/**
* A flag to include mixed evaluation
*/
public boolean mixed = true;
/**
* The output string
*/
public String output;
/**
* The temporary StringBuffer used to build the output String
*/
private StringBuffer out;
/**
* This class computes some quality measures (pixel-based, region-based, and
* mixed) between a binary detection result and a reference image, the
* results are gathered into an output string
*
* @param input
* The detection result to be evaluated
* @param reference
* The reference image
* @return The string containing evaluation results
*/
public static String exec(Image input, Image reference) {
return (String) new DetectionQualityEvaluation().process(input,
reference);
}
/**
* This class computes some quality measures (pixel-based, region-based, and
* mixed) between a binary detection result and a reference image, the
* results are gathered into an output string
*
* @param input
* The detection result to be evaluated
* @param reference
* The reference image
* @param pixel
* A flag to include pixel-based evaluation
* @param region
* A flag to include region-based evaluation
* @param mixed
* A flag to include mixed evaluation
* @return The string containing evaluation results
*/
public static String exec(Image input, Image reference, boolean pixel,
boolean region, boolean mixed) {
return (String) new DetectionQualityEvaluation().process(input,
reference, pixel, region, mixed);
}
/**
* Constructor
*
*/
public DetectionQualityEvaluation() {
super.inputs = "input,reference";
super.options = "pixel,region,mixed";
super.outputs = "output";
super.help = "computes some quality measures (pixel-based, region-based, and mixed)"
+ " between a binary detection result and a reference image, "
+ "the results are gathered into an output string\n"
+ "fr.unistra.pelican.Image evaluated image\n"
+ "fr.unistra.pelican.Image reference image\n"
+ "\n"
+ "java.lang.Boolean flag to include pixel-based evaluation\n"
+ "java.lang.Boolean flag to include region-based evaluation\n"
+ "java.lang.Boolean flag to include mixed evaluation\n"
+ "\n"
+ "java.lang.String evaluation results\n";
}
/*
* (non-Javadoc)
*
* @see fr.unistra.pelican.Algorithm#launch()
*/
public void launch() throws AlgorithmException {
out = new StringBuffer();
if (pixel)
evaluatePixel();
if (region)
evaluateRegion();
if (mixed)
evaluateMixte();
output=out.toString();
}
private void evaluatePixel() {
double total = input.size();
// Classif
double batiClassif = 0;
for (int p = 0; p < input.size(); p++)
if (input.getPixelBoolean(p))
batiClassif++;
double fondClassif = input.size() - batiClassif;
// Terrain
double batiTerrain = 0;
for (int p = 0; p < reference.size(); p++)
if (reference.getPixelBoolean(p))
batiTerrain++;
double fondTerrain = input.size() - batiTerrain;
// Bati - Bati
Image batibatiImg = AND.exec(input, reference); // correct
int batibati = 0;
for (int p = 0; p < batibatiImg.size(); p++)
if (batibatiImg.getPixelBoolean(p))
batibati++;
// Bati - Fond
Image batifondImg = CompareImage.exec(input, reference,
CompareImage.SUP); // faux positifs
int batifond = 0;
for (int p = 0; p < batifondImg.size(); p++)
if (batifondImg.getPixelBoolean(p))
batifond++;
// Fond - Bati
Image fondbatiImg = CompareImage.exec(reference, input,
CompareImage.SUP); // faux négatifs
int fondbati = 0;
for (int p = 0; p < fondbatiImg.size(); p++)
if (fondbatiImg.getPixelBoolean(p))
fondbati++;
// Fond - Fond
Image fondfondImg = OR.exec(input, reference); // fond
int fondfond = 0;
for (int p = 0; p < fondfondImg.size(); p++)
if (!fondfondImg.getPixelBoolean(p))
fondfond++;
out.append("\nEvaluation par pixels");
// Matrice de confusion
out.append("\n**** Matrice de confusion ****");
out.append("\n bati fond total");
out.append("\nbati " + batibati + " " + batifond + " "
+ (int) batiClassif);
out.append("\nfond " + fondbati + " " + fondfond + " "
+ (int) fondClassif);
out.append("\ntotal " + (int) batiTerrain + " " + (int) fondTerrain);
// Exactitude producteur
out.append("\n**** Qualité producteur ****");
out.append("\n\t bati = " + batibati / batiTerrain);
out.append("\n\t fond = " + fondfond / fondTerrain);
// Exactitude utilisateur
out.append("\n**** Qualité utilisateur ****");
out.append("\n\t bati = " + batibati / batiClassif);
out.append("\n\t fond = " + fondfond / fondClassif);
// Precision globale
double precision = (batibati + fondfond) / total;
out.append("\n**** Mesures globales ****");
out.append("\n\t précision = " + precision);
// Indice Kappa
double chance = (batiClassif * batiTerrain) / (total * total)
+ (fondClassif * fondTerrain) / (total * total);
double kappa = (precision - chance) / (1 - chance);
out.append("\n\t indice kappa = " + kappa);
out.append("\n");
}
private void evaluateRegion() {
double total = input.size();
// Classif
int batiClassif = (Integer) new BooleanConnectedComponentsLabeling()
.processOne(1, input, BooleanConnectedComponentsLabeling.CONNEXITY4);
// Terrain
int batiTerrain = (Integer) new BooleanConnectedComponentsLabeling()
.processOne(1, reference,
BooleanConnectedComponentsLabeling.CONNEXITY4);
// Bati - Bati
Image batibatiImg = AND.exec(input, reference); // correct
int batibati = (Integer) new BooleanConnectedComponentsLabeling().processOne(
1, batibatiImg, BooleanConnectedComponentsLabeling.CONNEXITY4);
// Bati - Fond
Image batifondImg = FastBinaryReconstruction.exec(batibatiImg, input,
FastBinaryReconstruction.CONNEXITY8);
int batifondImg2=(Integer) new BooleanConnectedComponentsLabeling().processOne(
1, batifondImg, BooleanConnectedComponentsLabeling.CONNEXITY4);
batifondImg = CompareImage.exec(input, batifondImg, CompareImage.SUP); // faux
// négatifs
int batifond = (Integer) new BooleanConnectedComponentsLabeling().processOne(
1, batifondImg, BooleanConnectedComponentsLabeling.CONNEXITY4);
// Fond - Bati
Image fondbatiImg = FastBinaryReconstruction.exec(batibatiImg,
reference, FastBinaryReconstruction.CONNEXITY8);
int fondbatiImg2=(Integer) new BooleanConnectedComponentsLabeling().processOne(
1, fondbatiImg, BooleanConnectedComponentsLabeling.CONNEXITY4);
fondbatiImg = CompareImage.exec(reference, fondbatiImg,
CompareImage.SUP); // faux négatifs
int fondbati = (Integer) new BooleanConnectedComponentsLabeling().processOne(
1, fondbatiImg, BooleanConnectedComponentsLabeling.CONNEXITY4);
out.append("\nEvaluation par régions");
// Matrice de confusion
out.append("\n**** Matrice de confusion ****");
out.append("\n bati fond total");
out.append("\nbati " + batibati + " " + batifond + " "
+ batiClassif);
out.append("\nfond " + fondbati + " ");
out.append("\ntotal " + batiTerrain);
// Exactitude producteur
out.append("\n**** Qualité producteur ****");
out.append("\n\t bati = " + fondbatiImg2 / (double) batiTerrain);
// Exactitude utilisateur
out.append("\n**** Qualité utilisateur ****");
out.append("\n\t bati = " + batifondImg2 / (double) batiClassif);
// Precision globale
out.append("\n**** Mesures globales ****");
double precision = (batibati)
/ ((double) (batibati + batifond + fondbati));
out.append("\n\tprécision = " + precision);
// Indice Kappa
double chance = (batiClassif * batiTerrain) / (total * total);
double kappa = (precision - chance) / (1 - chance);
out.append("\n\t indice kappa = " + kappa);
out.append("\n");
}
private void evaluateMixte() {
// Mise à jour du résultat
Image intersection = AND.exec(input, reference);
Image recIntRef = FastBinaryReconstruction.exec(intersection,
reference, FastBinaryReconstruction.CONNEXITY8);
Image recIntInp = FastBinaryReconstruction.exec(intersection, input,
FastBinaryReconstruction.CONNEXITY8);
Image ssIntInp = BinaryDifference.exec(input, recIntInp);
//Image ssIntRef = BinaryDifference.exec(input, recIntRef);
Image result = OR.exec(ssIntInp, recIntRef);
// Calcul par pixel
double total = input.size();
// Classif
double batiClassif = 0;
for (int p = 0; p < result.size(); p++)
if (result.getPixelBoolean(p))
batiClassif++;
double fondClassif = result.size() - batiClassif;
// Terrain
double batiTerrain = 0;
for (int p = 0; p < reference.size(); p++)
if (reference.getPixelBoolean(p))
batiTerrain++;
double fondTerrain = result.size() - batiTerrain;
// Bati - Bati
Image batibatiImg = AND.exec(result, reference); // correct
int batibati = 0;
for (int p = 0; p < batibatiImg.size(); p++)
if (batibatiImg.getPixelBoolean(p))
batibati++;
// Bati - Fond
Image batifondImg = CompareImage.exec(result, reference,
CompareImage.SUP); // faux positifs
int batifond = 0;
for (int p = 0; p < batifondImg.size(); p++)
if (batifondImg.getPixelBoolean(p))
batifond++;
// Fond - Bati
Image fondbatiImg = CompareImage.exec(reference, result,
CompareImage.SUP); // faux négatifs
int fondbati = 0;
for (int p = 0; p < fondbatiImg.size(); p++)
if (fondbatiImg.getPixelBoolean(p))
fondbati++;
// Fond - Fond
Image fondfondImg = OR.exec(result, reference); // fond
int fondfond = 0;
for (int p = 0; p < fondfondImg.size(); p++)
if (!fondfondImg.getPixelBoolean(p))
fondfond++;
out.append("\nEvaluation mixte");
// Matrice de confusion
out.append("\n**** Matrice de confusion ****");
out.append("\n bati fond total");
out.append("\nbati " + batibati + " " + batifond + " "
+ (int) batiClassif);
out.append("\nfond " + fondbati + " " + fondfond + " "
+ (int) fondClassif);
out.append("\ntotal " + (int) batiTerrain + " " + (int) fondTerrain);
// Exactitude producteur
out.append("\n**** Qualité producteur ****");
out.append("\n\t bati = " + batibati / batiTerrain);
out.append("\n\t fond = " + fondfond / fondTerrain);
// Exactitude utilisateur
out.append("\n**** Qualité utilisateur ****");
out.append("\n\t bati = " + batibati / batiClassif);
out.append("\n\t fond = " + fondfond / fondClassif);
// Precision globale
double precision = (batibati + fondfond) / total;
out.append("\n**** Mesures globales ****");
out.append("\n\t précision = " + precision);
// Indice Kappa
double chance = (batiClassif * batiTerrain) / (total * total)
+ (fondClassif * fondTerrain) / (total * total);
double kappa = (precision - chance) / (1 - chance);
out.append("\n\t indice kappa = " + kappa);
out.append("\n");
}
}