package graphmatcher.helper;
import graphmatcher.graph.Graph;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.Arrays;
import java.util.Random;
import java.util.Vector;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import Jama.Matrix;
public class TransformationEstimator {
private static Logger logger = Logger.getLogger(TransformationEstimator.class);
static {
logger.setLevel(Level.OFF);
}
public static EstimatedTransformationContainer lmsEstimator(Graph pattern, Graph template, int[] matching) {
long timeStart = System.currentTimeMillis();
Vector<Point> patternPoints = new Vector<Point>();
Vector<Point> templatePoints = new Vector<Point>();
for (int i = 0; i < matching.length; i++) {
if (matching[i] == -1) {
// nicht gematcht
continue;
}
patternPoints.add(pattern.vertices()[i].toPoint());
templatePoints.add(template.vertices()[matching[i]].toPoint());
}
int minPoints = Math.min(patternPoints.size(), templatePoints.size());
if (minPoints < 4) {
// logger.warn("zu wenig Knoten!");
throw new IllegalArgumentException(
"Zu wenig Knoten gematcht! Transformation kann nicht berechnet werden");
}
int MAX_ITER = 100;
Vector<EstimatedTransformationContainer> bestAffineTransform = new Vector<EstimatedTransformationContainer>();
EstimatedTransformationContainer dummyTap = new EstimatedTransformationContainer();
bestAffineTransform.add(dummyTap);
Point p1, p2, p3, q1, q2, q3;
Random random = new Random();
for (int iter = 0; iter < MAX_ITER; iter++) {
int r1, r2, r3;
if (minPoints > 10) {
r1 = random.nextInt(patternPoints.size());
r2 = random.nextInt(patternPoints.size());
while (r2 == r1) {
r2 = random.nextInt(patternPoints.size());
}
r3 = r2;
while ((r3 == r2) || (r3 == r1)) {
r3 = random.nextInt(patternPoints.size());
}
} else {
Vector<Integer> vector = new Vector<Integer>();
for (int i = 0; i < minPoints; i++) {
vector.add(i);
}
r1 = vector.remove(random.nextInt(vector.size()));
r2 = vector.remove(random.nextInt(vector.size()));
r3 = vector.remove(random.nextInt(vector.size()));
}
p1 = patternPoints.get(r1);
p2 = patternPoints.get(r2);
p3 = patternPoints.get(r3);
q1 = templatePoints.get(r1);
q2 = templatePoints.get(r2);
q3 = templatePoints.get(r3);
double[][] array1 = { { p1.x, p1.y, 1 }, { p2.x, p2.y, 1 }, { p3.x, p3.y, 1 } };
Matrix matrix = new Matrix(array1);
try {
double[][] vector1_ = { { q1.x }, { q2.x }, { q3.x } };
Matrix vector1 = new Matrix(vector1_);
Matrix result1 = matrix.solve(vector1);
double[][] zeile1 = result1.getArray();
double[][] vector2_ = { { q1.y }, { q2.y }, { q3.y } };
Matrix vector2 = new Matrix(vector2_);
Matrix result2 = matrix.solve(vector2);
double[][] zeile2 = result2.getArray();
double a11 = zeile1[0][0];
double a12 = zeile1[1][0];
double a13 = zeile1[2][0];
double a21 = zeile2[0][0];
double a22 = zeile2[1][0];
double a23 = zeile2[2][0];
AffineTransform affineTransform = new AffineTransform(a11, a21, a12, a22, a13, a23);
int medianMatchingEdgeLength = getMedianOfMatchingEdges(patternPoints, templatePoints,
affineTransform);
for (int i = 0; i < 2; i++) {
if (medianMatchingEdgeLength < bestAffineTransform.get(i).medianMatchingEdge) {
EstimatedTransformationContainer container = new EstimatedTransformationContainer();
container.affineTransform = affineTransform;
container.r1 = r1;
container.r2 = r2;
container.r3 = r3;
container.medianMatchingEdge = medianMatchingEdgeLength;
bestAffineTransform.add(i, container);
if (bestAffineTransform.size() > 2) {
bestAffineTransform.remove(2);
}
break;
}
}
} catch (Exception e) {
}
}
int size = bestAffineTransform.size();
if (size < 2) {
logger.warn("(TransformationEstimator) Vector kritisch: " + size);
}
// logger.info("0:" + bestAffineTransform.get(0).toString());
// logger.info("1:" + bestAffineTransform.get(1).toString());
EstimatedTransformationContainer result = bestAffineTransform.get(0);
result.time = System.currentTimeMillis() - timeStart;
return result;
}
/**
* Berechnet die L�nge aller Matchingkanten. Gibt die L�nge der mittleren
* zur�ck.
*
* @param patternPoints
* @param templatePoints
* @param affineTransform
* @return
*/
private static int getMedianOfMatchingEdges(Vector<Point> patternPoints, Vector<Point> templatePoints,
AffineTransform affineTransform) {
int[] lengthMatchingEdges = new int[patternPoints.size()];
for (int i = 0; i < patternPoints.size(); i++) {
Point patternPoint = patternPoints.get(i);
Point templatePoint = templatePoints.get(i);
Point transformedPatternPoint;
Point2D p = affineTransform.transform(patternPoint, null);
transformedPatternPoint = new Point((int) p.getX(), (int) p.getY());
double distance = DistanceHelper.getDistance(templatePoint, transformedPatternPoint);
lengthMatchingEdges[i] = (int) distance;
}
Arrays.sort(lengthMatchingEdges);
return lengthMatchingEdges[lengthMatchingEdges.length / 2];
}
}