package ie.dcu.auto; import ie.dcu.auto.automator.*; import ie.dcu.eval.*; import ie.dcu.matrix.ByteMatrix; import ie.dcu.segment.*; import java.io.IOException; import java.util.*; /** * Container class for data needed for the automation. * * @author Kevin McGuinness */ public class AutomationData { public static interface Listener { public void segmentationContextChanged(AutomationData data); public void segmentationContextUpdated(AutomationData automationData); public void groundTruthMaskChanged(AutomationData data); public void foregroundErrorChanged(AutomationData data); public void backgroundErrorChanged(AutomationData data); public void segmenterChanged(AutomationData data); public void evaluationMeasuresChanged(AutomationData data); public void evaluationResultsAdded(AutomationData data); public void evaluationResultsCleared(AutomationData data); public void automatorStateChanged(AutomationData data); public void logUpdated(AutomationData data, String message); } private SegmentationContext segmentationContext; private SegmentationMask groundTruthMask; private ByteMatrix foregroundError; private ByteMatrix backgroundError; private EvaluationResults evaluationResults; private List evaluators; private Segmenter segmenter; private Automator automator; private List listeners; public AutomationData() { evaluators = new LinkedList(); listeners = new LinkedList(); evaluationResults = new EvaluationResults(); automator = new DeterministicAutomator(this); } public void setAutomator(Automator automator) { if (automator == null) { throw new IllegalArgumentException(); } // Reset old automator this.automator.reset(); // Set new automator this.automator = automator; // Reset new automator this.automator.reset(); } public void dispose() { listeners.clear(); evaluators.clear(); setSegmentationContext(null); } public void addDefaultEvaluators() { addEvaluator(new BestEvaluator()); } public void addEvaluator(Evaluator e) { evaluators.add(e); updateEvaluationMeasures(); } public void removeEvaluator(Evaluator e) { evaluators.remove(e); updateEvaluationMeasures(); } public List getEvaluators() { return Collections.unmodifiableList(evaluators); } public SegmentationContext getSegmentationContext() { return segmentationContext; } public void setSegmentationContext(SegmentationContext context) { if (segmentationContext != context) { // Tidy up if (segmentationContext != null) { if (segmenter != null) { segmenter.finish(segmentationContext); } if (!segmentationContext.isDisposed()) { segmentationContext.dispose(); } segmentationContext = null; } // Set this.segmentationContext = context; fireSegmentationContextChanged(); } } public void setSegmenter(Segmenter segmenter) { if (this.segmenter != segmenter) { // Tidy up if (this.segmenter != null) { if (segmentationContext != null) { this.segmenter.finish(segmentationContext); } this.segmenter = null; } this.segmenter = segmenter; this.automator.reset(); fireSegmenterChanged(); } } public Segmenter getSegmenter() { return segmenter; } public SegmentationMask getGroundTruthMask() { return groundTruthMask; } public void setGroundTruthMask(SegmentationMask mask) { if (this.groundTruthMask != mask) { this.groundTruthMask = mask; fireGroundTruthMaskChanged(); } } public ByteMatrix getForegroundError() { return foregroundError; } public void setForegroundError(ByteMatrix error) { if (this.foregroundError != error) { this.foregroundError = error; fireForegroundErrorChanged(); } } public ByteMatrix getBackgroundError() { return backgroundError; } public void setBackgroundError(ByteMatrix error) { if (this.backgroundError != error) { this.backgroundError = error; fireBackgroundErrorChanged(); } } public void clearEvaluationResults() { if (evaluationResults.getResultCount() > 0) { evaluationResults.clearResults(); fireEvaluationResultsCleared(); } } private void updateEvaluationMeasures() { List headings = new ArrayList(); for (Evaluator e : evaluators) { String[] measures = e.getMeasures(); for (String m : measures) { headings.add(m); } } String[] measures = headings.toArray(new String[headings.size()]); setEvaluationMeasures(measures); } public void evaluate() { SegmentationMask mask = segmentationContext.getMask(); double[] values = new double[evaluationResults.getMeasureCount()]; for (Evaluator e : evaluators) { e.run(mask, groundTruthMask); String[] measures = e.getMeasures(); for (String m : measures) { int idx = evaluationResults.indexOfMeasure(m); values[idx] = e.getMeasure(m); } } addEvaluationResult(values); } private void addEvaluationResult(double[] result) { evaluationResults.addResults(result); fireEvaluationResultAdded(); } private void setEvaluationMeasures(String[] measures) { clearEvaluationResults(); evaluationResults.setMeasures(measures); fireEvaluationMeasuresChanged(); } public EvaluationResults getEvaluationResults() { return evaluationResults; } public Automator getAutomator() { return automator; } public void load(AutomationInput input) throws IOException { SegmentationContext ctx = SegmentationContext.create(input.imageFile); SegmentationMask mask = SegmentationMask.read(input.groundTruthFile); if (ctx.getBounds().equals(mask.getBounds())) { clearEvaluationResults(); setSegmentationContext(ctx); setGroundTruthMask(mask); automator.reset(); } else { ctx.dispose(); throw new IOException("Images are not the same size"); } } public void updateSegmentationError() { SegmentationMask mask = segmentationContext.getMask(); int rows = groundTruthMask.height; int cols = groundTruthMask.width; if (foregroundError == null || foregroundError.cols != cols || foregroundError.rows != rows) { foregroundError = new ByteMatrix(rows, cols); } if (backgroundError == null || backgroundError.cols != cols || backgroundError.rows != rows) { backgroundError = new ByteMatrix(rows, cols); } foregroundError.fill(0); backgroundError.fill(0); for (int i = 0; i < rows; i++) { int k = i * cols; for (int j = 0; j < cols; j++, k++) { int v = groundTruthMask.values[k]; if (v != mask.values[k]) { switch (v) { case SegmentationMask.FOREGROUND: foregroundError.values[k] = Constants.ERROR_VALUE; break; case SegmentationMask.BACKGROUND: backgroundError.values[k] = Constants.ERROR_VALUE; break; } } } } fireForegroundErrorChanged(); fireBackgroundErrorChanged(); } public void logActivity(String message, Object ... args) { String log = String.format(message, args) + "\n"; fireLogUpdated(log); } private void fireLogUpdated(String message) { for (Listener listener : listeners) { listener.logUpdated(this, message); } } private void fireSegmenterChanged() { for (Listener listener : listeners) { listener.segmenterChanged(this); } } private void fireForegroundErrorChanged() { for (Listener listener : listeners) { listener.foregroundErrorChanged(this); } } private void fireBackgroundErrorChanged() { for (Listener listener : listeners) { listener.backgroundErrorChanged(this); } } private void fireSegmentationContextChanged() { for (Listener listener : listeners) { listener.segmentationContextChanged(this); } } public void fireSegmentationContextUpdated() { for (Listener listener : listeners) { listener.segmentationContextUpdated(this); } } private void fireGroundTruthMaskChanged() { for (Listener listener : listeners) { listener.groundTruthMaskChanged(this); } } private void fireEvaluationMeasuresChanged() { for (Listener listener : listeners) { listener.evaluationMeasuresChanged(this); } } private void fireEvaluationResultAdded() { for (Listener listener : listeners) { listener.evaluationResultsAdded(this); } } private void fireEvaluationResultsCleared() { for (Listener listener : listeners) { listener.evaluationResultsCleared(this); } } public void fireAutomatorStateChanged() { for (Listener listener : listeners) { listener.automatorStateChanged(this); } } public void addListener(Listener listener) { listeners.add(listener); } public void removeListener(Listener listener) { listeners.remove(listener); } }