/*
* This file is part of the LIRE project: http://www.semanticmetadata.net/lire
* LIRE is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* LIRE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LIRE; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* We kindly ask you to refer the any or one of the following publications in
* any publication mentioning or employing Lire:
*
* Lux Mathias, Savvas A. Chatzichristofis. Lire: Lucene Image Retrieval –
* An Extensible Java CBIR Library. In proceedings of the 16th ACM International
* Conference on Multimedia, pp. 1085-1088, Vancouver, Canada, 2008
* URL: http://doi.acm.org/10.1145/1459359.1459577
*
* Lux Mathias. Content Based Image Retrieval with LIRE. In proceedings of the
* 19th ACM International Conference on Multimedia, pp. 735-738, Scottsdale,
* Arizona, USA, 2011
* URL: http://dl.acm.org/citation.cfm?id=2072432
*
* Mathias Lux, Oge Marques. Visual Information Retrieval using Java and LIRE
* Morgan & Claypool, 2013
* URL: http://www.morganclaypool.com/doi/abs/10.2200/S00468ED1V01Y201301ICR025
*
* Copyright statement:
* ====================
* (c) 2002-2013 by Mathias Lux (mathias@juggle.at)
* http://www.semanticmetadata.net/lire, http://www.lire-project.net
*
* Updated: 19.04.13 21:31
*/
package net.semanticmetadata.lire.imageanalysis.mser;
import net.semanticmetadata.lire.imageanalysis.mser.fourier.Fourier;
import net.semanticmetadata.lire.utils.SerializationUtils;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* Calculates Maximally stable extremal regions
* Algorithm based on Linear Time Maximally Stable Extremal Regions
* by David Nist_r and Henrik Stew_nius (2008)
* <p/>
* User: Shotty
* Date: 28.06.2010
* Time: 09:48:00
*/
public class MSER {
public static int MAX_GREY = 256;
private MSERParameter params;
private ImageMask imageMask;
private MSERHeap heap;
private Stack<MSERComponent> componentStack;
// all Extremal Regions
private ArrayList<MSERGrowthHistory> ers = new ArrayList<MSERGrowthHistory>();
// index of the parent in the arrayList of the extremal regions
// private int[] ersp = null;
private MSERGrowthHistory[] mers = null;
// TODO: find a suitable value
public static final double COARSE_ANGLE = Math.PI / 5;
public MSER() {
params = new MSERParameter();
}
public MSER(int delta,
double minArea, double maxArea,
double maxVariation, double minDiversity,
int maxEvolution, double areaThreshold,
double minMargin, int edgeBlurSize) {
params = new MSERParameter(delta, minArea, maxArea, maxVariation, minDiversity,
maxEvolution, areaThreshold, minMargin, edgeBlurSize);
}
/**
* Helper method to prepare the member fields before calculating the MSERs.
*/
private void prepare() {
for (int i = 0; i < ers.size(); i++) {
ers.get(i).setIndex(i);
}
}
public MSERGrowthHistory[] extractMSER(BufferedImage image) {
ers.clear();
// ersp = null;
mers = null;
int imageLength = image.getWidth() * image.getHeight();
// create the accessible pixel mask
imageMask = new ImageMask(image);
// create the heap of boundary pixels
heap = new MSERHeap(MAX_GREY);
// create component stack
componentStack = new Stack<MSERComponent>();
// push empty component on stack
// with level (grey value) which is not possible
componentStack.push(new MSERComponent(MAX_GREY));
// starting point is 0/0
BoundaryPixel currentPixel = imageMask.getBoundaryPixel(0);
imageMask.getAccess(currentPixel.getIndex());
int currentLevel = imageMask.getValue(currentPixel.getIndex());
// push component with currentLevel on stack
componentStack.push(new MSERComponent(currentLevel));
while (currentPixel != null) {
// explore the remaining edges
BoundaryPixel nextEdge = currentPixel.getNextBoundary();
while (nextEdge != null) {
if (!imageMask.hasAccess(nextEdge.getIndex())) {
// if pixel has no access yet, access it now
imageMask.getAccess(nextEdge.getIndex());
// if grayValue of edge is lower than current gray level
if (imageMask.getValue(nextEdge.getIndex()) < currentLevel) {
// enter the current pixel on boundary heap
heap.push(currentPixel, imageMask.getValue(currentPixel.getIndex()));
// edge is new pixel to consider
currentPixel = nextEdge;
currentLevel = imageMask.getValue(currentPixel.getIndex());
// push new Component onto Stack
componentStack.push(new MSERComponent(currentLevel));
} else {
// push the pixel on the heap
heap.push(nextEdge, imageMask.getValue(nextEdge.getIndex()));
}
}
// get the next edge
nextEdge = currentPixel.getNextBoundary();
}
assert (imageMask.getValue(currentPixel.getIndex()) == currentLevel);
assert (componentStack.peek().getGreyLevel() == currentLevel);
// System.out.println("ComponentStack.size:" + componentStack.size());
// accumulate the current pixel to the component on top of the stack
componentStack.peek().addPixel(currentPixel);
// pop the boundary heap
currentPixel = heap.pop();
if (currentPixel != null &&
imageMask.getValue(currentPixel.getIndex()) > currentLevel) {
// process all components on the component stack until we reach the higher gray level
processStack(imageMask.getValue(currentPixel.getIndex()));
// afterwards, this grey level is the current one
currentLevel = imageMask.getValue(currentPixel.getIndex());
} else if (currentPixel == null) {
// no pixels left, so just process the rest of the stack
processStack(MAX_GREY);
}
}
// System.out.println("ERS found: " + ers.size());
// now. calculate the maximally stable ones
prepare();
float[] areavar = new float[ers.size()];
boolean[] maxstable = new boolean[ers.size()];
int[] top = new int[ers.size()];
int[] bottom = new int[ers.size()];
for (int i = 0; i < ers.size(); i++) {
top[i] = imageLength;
}
/*
* Calculate the R+delta and R-delta as described in [2].
*
*/
for (int i = 0; i < ers.size(); i++) {
// always starting region
MSERGrowthHistory region = ers.get(i);
int valr0 = region.maxGreyValue;
// always current region
MSERGrowthHistory actRegion = region;
int valri = actRegion.maxGreyValue;
// always parent region of actRegion
MSERGrowthHistory parent = actRegion.getParent();
// always greyValue of direct parent of the LOW region
int valr1 = parent.maxGreyValue;
while (true) {
// always greyValue of the parent of the current regions
int valp = parent.maxGreyValue;
/**
* Region is R-delta of actRegion
* VAL (r0) <= VAL (ri) - DELTA < VAL (r1)
*/
if (valr0 <= valri - params.delta && valri - params.delta < valr1) {
bottom[actRegion.getIndex()] = Math.max(bottom[actRegion.getIndex()], region.getSize());
}
/**
* actRegion is R+delta of region
* VAL(ri) <= VAL(x0) + DELTA < VAL(ri + 1)
*/
if (valri <= valr0 + params.delta && valr0 + params.delta < valp) {
top[region.getIndex()] = actRegion.getSize();
}
/**
* Stop if going on is useless
*
* VAL(r1) <= VAL(ri) - DELTA --> No bottom can be found anymore
* VAL(ri) > VAL(r0) + DELTA --> no top can be found anymore
*/
if (valr1 <= valri - params.delta && valr0 + params.delta < valri) {
break;
}
/**
* The root is reached
*/
if (actRegion == parent) {
break;
}
actRegion = parent; // current region is now the parent
valri = actRegion.maxGreyValue; // grey value of current region;
parent = actRegion.getParent(); // get parent of current region
}
}
/*
* Calculate the areavariation
*/
for (int i = 0; i < ers.size(); i++) {
MSERGrowthHistory er = ers.get(i);
int atop = top[er.getIndex()];
int abot = bottom[er.getIndex()];
areavar[i] = (float) (atop - abot) / (float) er.getSize();
maxstable[i] = true;
}
// To take into account, that an ER is maximally stable if it has a local minimum regarding any of its child.
// But it makes no difference.
//boolean[] visited = new boolean[ers.size()];*/ //initialized to false
/*
* Remove not maximally stable ERs.
*/
int maxcount = ers.size();
for (int i = 0; i < ers.size(); i++) {
MSERGrowthHistory er = ers.get(i);
float var = areavar[i];
float pvar = areavar[er.getParent().getIndex()];
int notstable;
if (er.getParent().maxGreyValue == er.maxGreyValue + 1) {
if ((var < pvar) /*&& (!visited[ersp[i]])*/) {
notstable = er.getParent().getIndex();
} else {
notstable = i;
/*visited[ersp[i]] = true;*/
}
if (maxstable[notstable]) {
maxcount--;
maxstable[notstable] = false;
}
}
}
int imaxsize = (int) (imageLength * params.maxArea);
int iminsize = (int) (imageLength * params.minArea);
// System.out.println("Iminsize" + iminsize);
/*
* Here clean up is done to remove low descriptive MSERs.
* ERs are ordered in ers by increasing size (because of how they are added. Not absolute but relative to parent - child resp. set - subset relation).
* For removing duplicates we must go from larger to smaller ones, otherwise is can happen that a child is removed because it is too similar with
* its parent and then the parent is removed because of an other reason.
*/
for (int i = ers.size() - 1; i >= 0; i--) { //for(int i = 0; i < ers.size(); i++){
if (maxstable[i]) {
boolean remove = false;
MSERGrowthHistory er = ers.get(i);
// Remove too big ones
if (er.getSize() > imaxsize) {
remove = true;
}
// Remove too small ones
// should at least have 25 px that mser!!
if (er.getSize() < iminsize || er.getSize() < 25) {
remove = true;
}
// Remove with high area variation
if (areavar[i] >= params.maxVariation) {
remove = true;
}
// Remove duplicates
if (!remove) {
int parent = er.getParent().getIndex();
if (parent != i) {
// get first STABLE parent - or go through till the root
while (!maxstable[parent] && parent != ers.get(parent).getParent().getIndex()) {
parent = ers.get(parent).getParent().getIndex();
}
// if a stable parent was found
if (maxstable[parent]) {
int parea = ers.get(parent).getSize();
float d = (float) (parea - er.getSize()) / (float) er.getSize();
if ((d < params.minDiversity)) { //&& ( parea < imaxsize )
remove = true;
}
}
}
}
if (remove) {
maxstable[i] = false;
maxcount--;
}
}
}
int idx = 0;
mers = new MSERGrowthHistory[maxcount];
for (int i = 0; i < ers.size(); i++) {
if (maxstable[i]) {
mers[idx++] = ers.get(i);
// System.out.println(i);
// for (ImagePoint ip : ers.get(i).getPoints())
// {
// System.out.print(ip.getIndex());
// }
}
}
// System.out.println("Found maximally stable regions:" + maxcount);
return mers;
}
protected void processStack(int newPixelGreyLevel) {
// System.out.println("newPixelGreyLevel:" + newPixelGreyLevel);
// while the new pixel grey level is bigger than the grey level of the top stack
while (newPixelGreyLevel > componentStack.peek().getGreyLevel()) {
// System.out.println("secondComp.greyLevel:" + componentStack.peek().getGreyLevel());
// pop top-stack element for access to the second component
MSERComponent topOfStack = componentStack.pop();
// top of stack is ER
topOfStack.addHistory();
ers.add(topOfStack.getHistory());
if (newPixelGreyLevel < componentStack.peek().getGreyLevel()) {
// set top of stack gray level to newPixelGreyLevel
topOfStack.setGreyLevel(newPixelGreyLevel);
// push it on the stack again and return
componentStack.push(topOfStack);
} else {
// merge two components
// the winner is the one which is bigger - but only finished EXTREMAL Regions are
// taken into account - this means that the component still on the stack
// cannot be considered finished, so the history size is taken (if available)
if (topOfStack.getSize() >= componentStack.peek().getPastSize()) {
// topOfStack is winner
MSERComponent second = componentStack.pop();
topOfStack.mergeComponents(second, second.getGreyLevel());
// add the topOfStack
componentStack.push(topOfStack);
} else {
// second stack is winner
componentStack.peek().mergeComponents(topOfStack, componentStack.peek().getGreyLevel());
}
}
}
}
public List<MSERFeature> computeMSERFeatures(BufferedImage image) {
MSERGrowthHistory[] msers = extractMSER(image);
return computeFourier(msers, image.getWidth(), image.getHeight());
}
public List<MSERFeature> computeFourier(MSERGrowthHistory[] msers, int width, int height) {
List<MSERFeature> features = new ArrayList<MSERFeature>();
// compute Fourier
for (MSERGrowthHistory mser : msers) {
// getBorderPoints closes the shape already
// This a problem with coarsenPoly!!
ImagePoint[] border = mser.getBorderPoints(width, height);
// so the last point is omitted
double[][] coarsedPoly = coarsenPoly(
pointToMatrix(border, border.length - 1), COARSE_ANGLE);
// TODO: check if there is a problem with coarsenPoly
// calculate the Fourier descriptors
Fourier f = new Fourier(matrixToPoints(coarsedPoly, true));
// compute Fourier with 32 variables
f.computeFourier(32);
// create affine invariant variables
f.createInvariants2(1);
features.add(new MSERFeature(mser, SerializationUtils.toDoubleArray(f.getInvariants())));
}
return features;
}
public Point2D.Double[] matrixToPoints(double[][] coarsedPoly, boolean closeShape) {
int n = (closeShape) ? coarsedPoly[0].length + 1 : coarsedPoly[0].length;
int mod = coarsedPoly[0].length;
Point2D.Double[] points = new Point2D.Double[n];
for (int i = 0; i < n; i++) {
points[i] = new Point2D.Double(coarsedPoly[0][i % mod],
coarsedPoly[1][i % mod]);
}
return points;
}
/**
* implementation of cyclic translation for matrices.
*
* @param matrix arbitrary typed matrix to be translated
* @param m Shift in y-Direction = first matrix-dimension!
* @param n Shift in x-Direction = second matrix-dimension!
* @return cyclic translated matrix, e.g.
* cycltrans([1 2 3; 4 5 6; 7 8 9], 1,1)
* = [5 6 4; 8 9 7 ; 2 3 1]
*/
protected double[][] cycltrans(double[][] matrix, int m, int n) {
int ys = matrix.length;
int xs = matrix[0].length;
m = ((m % ys) + ys) % ys;
n = ((n % xs) + xs) % xs;
double[][] doublematrix = new double[ys + ys][xs + xs];
for (int i = 0; i < doublematrix.length; i++) {
for (int j = 0; j < doublematrix[i].length; j++) {
doublematrix[i][j] = matrix[i % ys][j % xs];
}
}
double[][] res = new double[ys][xs];
for (int i = 0; i < ys; i++) {
for (int j = 0; j < xs; j++) {
res[i][j] = doublematrix[i + m % ys][j + n % xs];
}
}
// printMatrix("RES", res);
return res;
}
public double[][] coarsenPoly(double[][] p, double angle) {
// finding the number of indices of p
int n = p[0].length;
// printMatrix("P", p);
double[][] q = cycltrans(p, 0, 1);
// printMatrix("Q", q);
// finding the internal angles of the polygon p
// formula: internal angle a = acos(-v1.v2/ |v1|.|v2|) where
// v1 v2 are the line vectors of the sides of the polygon p
double[][] v1 = new double[2][n];
for (int i = 0; i < n; i++) {
v1[0][i] = q[0][i] - p[0][i];
v1[1][i] = q[1][i] - p[1][i];
}
// printMatrix("V1", v1);
double[][] v2 = cycltrans(v1, 0, 1);
// printMatrix("V2", v2);
// num = v1.v2, dot product of the two line vectors
double[][] dp = new double[2][n];
double[] num = new double[n];
for (int i = 0; i < n; i++) {
dp[0][i] = v1[0][i] * v2[0][i];
dp[1][i] = v1[1][i] * v2[1][i];
num[i] = dp[0][i] + dp[1][i];
}
// printMatrix("DP", dp);
// printArray("NUM", num);
// l1 and l2 are | v1 |, | v2 | simultaneously
double[] l1 = new double[n];
double[] l2 = new double[n];
double[] den = new double[n];
for (int i = 0; i < n; i++) {
l1[i] = Math.sqrt(v1[0][i] * v1[0][i] + v1[1][i] * v1[1][i]);
l2[i] = Math.sqrt(v2[0][i] * v2[0][i] + v2[1][i] * v2[1][i]);
den[i] = l1[i] * l2[i];
}
// printArray("L1", l1);
// printArray("L2", l2);
// printArray("DEN", den);
// 'a' is a 1*s matrix with all the internal angles of polygon p.
double[] a = new double[n];
int counter = 0;
for (int i = 0; i < n; i++) {
a[i] = Math.acos(-num[i] / den[i]);
if (a[i] <= (Math.PI - angle)) counter++;
}
// printArray("A", a);
// selecting all indices of q with internal angle <= %pi-t into cq
double[][] cq = new double[2][counter];
counter = 0;
for (int i = 0; i < n; i++) {
if (a[i] <= (Math.PI - angle)) {
cq[0][counter] = q[0][i];
cq[1][counter++] = q[1][i];
}
}
// printMatrix("CQ", cq);
// if last of cq equals last of q then shift is necessary
// else cq is result;
if (cq[0][cq[0].length - 1] == q[0][q[0].length - 1] &&
cq[1][cq[1].length - 1] == q[1][q[1].length - 1]) {
return cycltrans(cq, 0, -1);
} else {
return cq;
}
}
/*public static void main(String[] args) {
double[][] matrix = new double[3][2];
matrix[0] = new double[]{1, 2};
matrix[1] = new double[]{4, 5};
matrix[2] = new double[]{7, 8};
printMatrix("1", matrix);
matrix = cycltrans(matrix, 1, 0);
printMatrix("2", matrix);
Point2D.Double[] poly = new Point2D.Double[10];
poly[0] = new Point2D.Double(4, 0);
poly[1] = new Point2D.Double(2.427051, 1.7633558);
poly[2] = new Point2D.Double(1.236068, 3.8042261);
poly[3] = new Point2D.Double(-0.9270510, 2.8531695);
poly[4] = new Point2D.Double(-3.236068, 2.351141);
// poly[5] = new Point2D.Double(-3, 4.441D-16);
poly[5] = new Point2D.Double(-3, 4.441e-16);
poly[6] = new Point2D.Double(-3.236068, -2.351141);
poly[7] = new Point2D.Double(-0.9270510, -2.8531695);
poly[8] = new Point2D.Double(1.236068, -3.8042261);
poly[9] = new Point2D.Double(2.427051, -1.7633558);
poly = matrixToPoints(coarsenPoly(pointToMatrix(poly), Math.PI / 4), true);
printPoints("POLY", poly);
poly = new Point2D.Double[55];
poly[0] = new Point2D.Double(199, 3);
poly[1] = new Point2D.Double(200, 4);
poly[2] = new Point2D.Double(201, 5);
poly[3] = new Point2D.Double(202, 5);
poly[4] = new Point2D.Double(203, 6);
poly[5] = new Point2D.Double(204, 7);
poly[6] = new Point2D.Double(204, 8);
poly[7] = new Point2D.Double(204, 9);
poly[8] = new Point2D.Double(203, 10);
poly[9] = new Point2D.Double(202, 11);
poly[10] = new Point2D.Double(202, 12);
poly[11] = new Point2D.Double(202, 13);
poly[12] = new Point2D.Double(202, 14);
poly[13] = new Point2D.Double(202, 15);
poly[14] = new Point2D.Double(202, 16);
poly[15] = new Point2D.Double(202, 17);
poly[16] = new Point2D.Double(202, 18);
poly[17] = new Point2D.Double(202, 19);
poly[18] = new Point2D.Double(202, 20);
poly[19] = new Point2D.Double(202, 21);
poly[20] = new Point2D.Double(202, 22);
poly[21] = new Point2D.Double(202, 23);
poly[22] = new Point2D.Double(203, 24);
poly[23] = new Point2D.Double(204, 24);
poly[24] = new Point2D.Double(205, 23);
poly[25] = new Point2D.Double(205, 22);
poly[26] = new Point2D.Double(206, 21);
poly[27] = new Point2D.Double(207, 21);
poly[28] = new Point2D.Double(208, 20);
poly[29] = new Point2D.Double(208, 19);
poly[30] = new Point2D.Double(209, 18);
poly[31] = new Point2D.Double(209, 17);
poly[32] = new Point2D.Double(210, 16);
poly[33] = new Point2D.Double(211, 16);
poly[34] = new Point2D.Double(211, 15);
poly[35] = new Point2D.Double(211, 14);
poly[36] = new Point2D.Double(211, 13);
poly[37] = new Point2D.Double(211, 12);
poly[38] = new Point2D.Double(211, 11);
poly[39] = new Point2D.Double(211, 10);
poly[40] = new Point2D.Double(212, 9);
poly[41] = new Point2D.Double(212, 8);
poly[42] = new Point2D.Double(212, 7);
poly[43] = new Point2D.Double(211, 6);
poly[44] = new Point2D.Double(210, 5);
poly[45] = new Point2D.Double(209, 4);
poly[46] = new Point2D.Double(208, 4);
poly[47] = new Point2D.Double(207, 4);
poly[48] = new Point2D.Double(206, 4);
poly[49] = new Point2D.Double(205, 4);
poly[50] = new Point2D.Double(204, 4);
poly[51] = new Point2D.Double(203, 4);
poly[52] = new Point2D.Double(202, 4);
poly[53] = new Point2D.Double(201, 3);
poly[54] = new Point2D.Double(200, 3);
// poly[55] = new Point2D.Double(199,3);
poly = matrixToPoints(coarsenPoly(pointToMatrix(poly), Math.PI / 5), false);
printPoints("POLY", poly);
poly = new Point2D.Double[57];
poly[0] = new Point2D.Double(364, 0);
poly[1] = new Point2D.Double(364, 1);
poly[2] = new Point2D.Double(363, 2);
poly[3] = new Point2D.Double(363, 3);
poly[4] = new Point2D.Double(363, 4);
poly[5] = new Point2D.Double(363, 5);
poly[6] = new Point2D.Double(363, 6);
poly[7] = new Point2D.Double(363, 7);
poly[8] = new Point2D.Double(363, 8);
poly[9] = new Point2D.Double(363, 9);
poly[10] = new Point2D.Double(363, 10);
poly[11] = new Point2D.Double(363, 11);
poly[12] = new Point2D.Double(363, 12);
poly[13] = new Point2D.Double(364, 13);
poly[14] = new Point2D.Double(364, 14);
poly[15] = new Point2D.Double(364, 15);
poly[16] = new Point2D.Double(365, 16);
poly[17] = new Point2D.Double(366, 17);
poly[18] = new Point2D.Double(366, 18);
poly[19] = new Point2D.Double(367, 19);
poly[20] = new Point2D.Double(367, 20);
poly[21] = new Point2D.Double(367, 21);
poly[22] = new Point2D.Double(368, 22);
poly[23] = new Point2D.Double(369, 22);
poly[24] = new Point2D.Double(370, 22);
poly[25] = new Point2D.Double(371, 22);
poly[26] = new Point2D.Double(372, 22);
poly[27] = new Point2D.Double(373, 21);
poly[28] = new Point2D.Double(373, 20);
poly[29] = new Point2D.Double(373, 19);
poly[30] = new Point2D.Double(373, 18);
poly[31] = new Point2D.Double(373, 17);
poly[32] = new Point2D.Double(373, 16);
poly[33] = new Point2D.Double(373, 15);
poly[34] = new Point2D.Double(373, 14);
poly[35] = new Point2D.Double(373, 13);
poly[36] = new Point2D.Double(373, 12);
poly[37] = new Point2D.Double(373, 11);
poly[38] = new Point2D.Double(373, 10);
poly[39] = new Point2D.Double(373, 9);
poly[40] = new Point2D.Double(373, 8);
poly[41] = new Point2D.Double(373, 7);
poly[42] = new Point2D.Double(373, 6);
poly[43] = new Point2D.Double(373, 5);
poly[44] = new Point2D.Double(373, 4);
poly[45] = new Point2D.Double(373, 3);
poly[46] = new Point2D.Double(373, 2);
poly[47] = new Point2D.Double(373, 1);
poly[48] = new Point2D.Double(373, 0);
poly[49] = new Point2D.Double(372, 0);
poly[50] = new Point2D.Double(371, 0);
poly[51] = new Point2D.Double(370, 0);
poly[52] = new Point2D.Double(369, 0);
poly[53] = new Point2D.Double(368, 0);
poly[54] = new Point2D.Double(367, 0);
poly[55] = new Point2D.Double(366, 0);
poly[56] = new Point2D.Double(365, 0);
poly = matrixToPoints(coarsenPoly(pointToMatrix(poly), Math.PI / 8), false);
printPoints("POLY", poly);
/*
// gerades F
Point2D.Double[] EF =
{
new Point2D.Double(0/2.,0/2.),
new Point2D.Double(2/2.,0/2.),
new Point2D.Double(2/2.,5/2.),
new Point2D.Double(5/2.,5/2.),
new Point2D.Double(5/2.,7/2.),
new Point2D.Double(2/2.,7/2.),
new Point2D.Double(2/2.,9/2.),
new Point2D.Double(7/2.,9/2.),
new Point2D.Double(7/2.,11/2.),
new Point2D.Double(0/2.,11/2.),
new Point2D.Double(0/2.,0/2.) // X(N) == X(0))
};
testFourier(EF, 5);
*/
// }
public double[][] pointToMatrix(Point2D.Double[] poly) {
double[][] res = new double[2][poly.length];
for (int i = 0; i < poly.length; i++) {
res[0][i] = poly[i].getX();
res[1][i] = poly[i].getY();
}
return res;
}
/**
* @param poly the poly to transform
* @param length length of the matrix
* @return a matrix of the values
*/
public double[][] pointToMatrix(ImagePoint[] poly, int length) {
double[][] res = new double[2][length];
for (int i = 0; i < length; i++) {
res[0][i] = poly[i].getX();
res[1][i] = poly[i].getY();
}
return res;
}
public void printMatrix(String name, double[][] matrix) {
System.out.println("MATRIX " + name + ":");
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j]);
System.out.print(",");
}
System.out.println();
}
}
@SuppressWarnings("unused")
private void printArray(String name, double[] array) {
System.out.println("ARRAY " + name + ":");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]);
System.out.print(",");
System.out.println();
}
}
public void printPoints(String name, Point2D.Double[] points) {
System.out.println("points " + name + ":");
for (int i = 0; i < points.length; i++) {
System.out.print("," + points[i].getX() + "," + points[i].getY());
}
}
public static void printPoints(String name, ImagePoint[] points) {
System.out.println("points " + name + ":");
for (int i = 0; i < points.length; i++) {
// System.out.print("," + points[i].getIndex());
System.out.print("," + points[i].toString());
// System.out.println("poly[" + i + "] = new Point2D.Double(" + points[i].toString()+ ");");
}
}
}