package fr.unistra.pelican.util.morphology;
import java.awt.Point;
import fr.unistra.pelican.BooleanImage;
import fr.unistra.pelican.Image;
/**
* Describes a flat structuring element.
*
* +added diagonal lines.02/06
* @deprecated
*/
public class FlatStructuringElement extends BooleanImage implements
StructuringElement {
private int rows = getYDim();
private int cols = getXDim();
/**
*
*/
public static final long serialVersionUID = 234523;
// present and future bug source:
// the centre is kept as X,Y being : COLUMS, ROWS.
// Careful with the transformations
// TODO E.A : we should use a single standard...this is far too messy.
private Point centre;
private Point[] points = null;
/**
* copy constructor with no pixel cloning
*
* @param e
* the structuring element to clone.
*/
public FlatStructuringElement(FlatStructuringElement e) {
super(e.getColumns(), e.getRows(), 1, 1, 1);
this.centre = (Point) e.getCenter().clone();
}
public FlatStructuringElement copyImage(boolean copy) {
return new FlatStructuringElement(this, copy);
}
/**
*
* @param se
* @param copy
*/
public FlatStructuringElement(FlatStructuringElement se, boolean copy) {
super(se);
this.centre = (Point) se.getCenter().clone();
if (copy == true)
this.setPixels((boolean[]) se.getPixels().clone());
else
this.setPixels(new boolean[se.getXDim() * se.getYDim() * 1 * 1 * 1]);
}
/**
* Contruct a new structuring element.
*
* @param rows
* number of rows.
* @param cols
* number of columns.
*/
public FlatStructuringElement(int rows, int cols) {
super(cols, rows, 1, 1, 1);
}
/**
* @param rows
* rows number of rows.
* @param cols
* cols number of columns.
* @param centre
* center of the structuring element.
*/
public FlatStructuringElement(int rows, int cols, Point centre) {
super(cols, rows, 1, 1, 1);
this.centre = (Point) centre.clone();
}
/**
* @param values
* image of the shape to clone.
*/
public void setValues(boolean[] values) {
setPixels(values);
}
/**
* @param col
* @param row
* @return if the pixel is active
*/
public boolean isValue(int row, int col) {
return getPixelBoolean(row * cols + col);
}
/**
* @param center
*/
public void setCenter(Point center) {
this.centre = center;
}
/**
* @return the center in Colums,Rows format
*/
// public Point getCenter() {
// return centre;
// }
/**
* @return the number of rows
*/
public int getRows() {
return this.rows;
}
/**
* @return the number of colums
*/
public int getColumns() {
return this.cols;
}
/**
* @param b
* the value to set in each pixel of the structuring element.
*/
public void fill(boolean b) {
super.fill(b);
}
/**
* Create a vertical line of length length. The center is at length/2
*
* @param length
* @return a vertical line shaped SE
*/
public static FlatStructuringElement createVerticalLineFlatStructuringElement(
int length) {
FlatStructuringElement se = new FlatStructuringElement(length, 1,
new Point(0, length / 2));
se.fill(true);
return se;
}
/**
* Create a left diagonal line of length length (odd). The center is at
* length / 2
*
* @param length
* @return a left diagonal shaped SE
*/
public static FlatStructuringElement createLeftDiagonalLineFlatStructuringElement(
int length) {
FlatStructuringElement se = new FlatStructuringElement(length, length,
new Point(length / 2, length / 2));
for (int i = 0; i < length; i++)
se.setValue(i, i, true);
return se;
}
/**
* Create a right diagonal line of length length (odd). The center is at
* length / 2
*
* @param length
* @return
*/
public static FlatStructuringElement createRightDiagonalLineFlatStructuringElement(
int length) {
FlatStructuringElement se = new FlatStructuringElement(length, length,
new Point(length / 2, length / 2));
for (int i = 0; i < length; i++)
se.setValue(length - 1 - i, i, true);
return se;
}
/**
* Create a horizontal line of length length. The center is at length/2.
*
* @param length
* @param center
* @return
*/
public static FlatStructuringElement createHorizontalLineFlatStructuringElement(
int length) {
FlatStructuringElement se = new FlatStructuringElement(1, length,
new Point(length / 2, 0));
se.fill(true);
return se;
}
/**
* Create a line of length length of a given orientation (in degrees)
*
* @param length
* @param orientation
* @return
*/
public static FlatStructuringElement createLineFlatStructuringElement(
int length, int orientation) {
double cos = Math.cos(Math.toRadians(orientation));
double sin = Math.sin(Math.toRadians(orientation));
double abscos = Math.abs(cos);
double abssin = Math.abs(sin);
double epsilon = 0.0000001;
double sumcos = abscos;
double sumsin = abssin;
int i = 0, j = 0;
int center = (length - 1) / 2;
FlatStructuringElement se = new FlatStructuringElement(length, length,
new Point(center, center));
se.setValue(center, center, true);
for (int l = 1; l <= center; l++) {
if (sumcos + epsilon >= sumsin) {
i = cos > 0 ? i + 1 : i - 1;
sumsin += abssin;
}
if (sumsin + epsilon >= sumcos) {
j = sin > 0 ? j + 1 : j - 1;
sumcos += abscos;
}
se.setValue(center + j, center + i, true);
se.setValue(center - j, center - i, true);
}
return se;
}
/**
* Create a horizontal line of length length. The center is at center.
*
* @param length
* @param center
* @return
*/
public static FlatStructuringElement createHorizontalLineFlatStructuringElement(
int length, Point center) {
FlatStructuringElement se = new FlatStructuringElement(1, length,
center);
se.fill(true);
return se;
}
/**
* Create a cross line of radius radius (plus the pixel at the cross).
*
* @param radius
* @return
*/
public static FlatStructuringElement createCrossFlatStructuringElement(
int radius) {
FlatStructuringElement se = new FlatStructuringElement(2 * radius + 1,
2 * radius + 1, new Point(radius, radius));
for (int i = 0; i < 2 * radius + 1; i++) {
se.setValue(i, radius, true);
se.setValue(radius, i, true);
}
return se;
}
/**
* Create a circle of radius radius (plus the pixel at the cross).
*
* @param radius
* @return
*/
public static FlatStructuringElement createCircleFlatStructuringElement(
int radius) {
FlatStructuringElement se = new FlatStructuringElement(2 * radius + 1,
2 * radius + 1, new Point(radius, radius));
for (int i = 0; i < 2 * radius + 1; i++) {
for (int j = 0; j < 2 * radius + 1; j++) {
if (Math
.sqrt(Math.pow(i - radius, 2) + Math.pow(j - radius, 2)) <= radius + 0.000001)
se.setValue(i, j, true);
}
}
return se;
}
public void setValue(int row, int col, boolean b) {
setPixelBoolean(row * cols + col,b);
}
public void setValue(int location, boolean b) {
setPixelBoolean(location,b);
}
public boolean getValue(int row, int col) {
return getPixelBoolean(row * cols + col);
}
/**
* @return The transpose of the structuring element.
*/
public FlatStructuringElement getTranspose() {
FlatStructuringElement se = new FlatStructuringElement(this);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
se.setValue(i, j, this.getValue(cols - j - 1, rows - i - 1));
se.setCenter(new Point(this.cols - this.centre.x - 1, this.rows - 1
- centre.y));
return se;
}
/**
* Create a square of edge's length size. Center is at (size/2, size/2).
*
* @param size
* @return a square SE
*/
public static FlatStructuringElement createSquareFlatStructuringElement(
int size) {
FlatStructuringElement se = new FlatStructuringElement(size, size,
new Point(size / 2, size / 2));
se.fill(true);
return se;
}
/**
* Create a diamond of a given height (width is the same). Center is at
* (size/2, size/2).
*
* @param size
* @return a square SE
*/
public static FlatStructuringElement createDiamondFlatStructuringElement(
int size) {
FlatStructuringElement se = new FlatStructuringElement(size, size,
new Point(size / 2, size / 2));
for (int x = 0; x < se.getXDim(); x++)
for (int y = 0; y < se.getYDim(); y++)
if (x + y + 1 > size / 2 && y <= size / 2 + x
&& x + y + 1 <= size + size / 2 && x - y <= size / 2)
se.setPixelXYBoolean(x, y, true);
else
se.setPixelXYBoolean(x, y, false);
return se;
}
/**
* Create a rectangle. Center is at (height/2, width/2).
*
* @param rows
* @param cols
* @return a rectangle shaped SE
*/
public static FlatStructuringElement createRectangularFlatStructuringElement(
int rows, int cols) {
FlatStructuringElement se = new FlatStructuringElement(rows, cols,
new Point(cols / 2, rows / 2));
se.fill(true);
return se;
}
/**
* Create a hollow square SE element size x size. Center is at (size/2,
* size/2).
*
* @param size
* @return a hollow square SE
*/
public static FlatStructuringElement createHollowSquareFlatStructuringElement(
int size) {
FlatStructuringElement se = new FlatStructuringElement(size, size,
new Point(size / 2, size / 2));
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
if (x == 0 || x == size - 1 || y == 0 || y == size - 1)
se.setPixelXYBoolean(x, y, true);
}
}
return se;
}
/**
* Create a frame rectangle. Center is at (height/2, width/2).
*
* @param rows
* @param cols
* @return
*/
public static FlatStructuringElement createFrameFlatStructuringElement(
int rows, int cols) {
FlatStructuringElement se = new FlatStructuringElement(rows, cols,
new Point(cols / 2, rows / 2));
se.fill(false);
for (int i = 0; i < rows; i++) {
se.setValue(i, 0, true);
se.setValue(i, cols - 1, true);
}
for (int i = 0; i < cols; i++) {
se.setValue(0, i, true);
se.setValue(rows - 1, i, true);
}
return se;
}
/**
* Create a frame square of edge's length size. Center is at (size/2,
* size/2).
*
* @param size
* @return
*/
public static FlatStructuringElement createFrameFlatStructuringElement(
int size) {
return createFrameFlatStructuringElement(size, size);
}
/**
*
* @param se1
* @param se2
* @return
*/
public static boolean haveSameCentre(FlatStructuringElement se1,
FlatStructuringElement se2) {
return se1.getCenter().equals(se2.getCenter());
}
public boolean[] getValues() {
return getPixels();
}
/**
* @return true is this structuring element have 2n pixel set as true.
*/
public boolean isOdd() {
return (this.howManyPoints() % 2 == 1);
}
/**
* @return The number of pixels sets as true.
*/
public int howManyPoints() {
int cnt = 0;
for (int i = 0; i < this.size(); i++)
if (getPixelBoolean(i) == true)
cnt++;
return cnt;
}
public FlatStructuringElement rotate(double degree) {
double angleradian = Math.toRadians(degree);
double xinput = this.cols;
double yinput = this.rows;
double tcos = Math.cos(-angleradian);
double tsin = Math.sin(-angleradian);
double atcos = Math.cos(angleradian);
double atsin = Math.sin(angleradian);
int xoutput = (int) Math.round(xinput * Math.abs(tcos) + yinput
* Math.abs(tsin));
int youtput = (int) Math.round(xinput * Math.abs(tsin) + yinput
* Math.abs(tcos));
// System.out.println(xoutput + " " + youtput + " ... "
// + (xinput * Math.abs(tcos) + yinput * Math.abs(tsin)) + " "
// + (xinput * Math.abs(tsin) + yinput * Math.abs(tcos)));
int xm = this.cols / 2;
int ym = this.rows / 2;
int xmprime = xoutput / 2;
int ymprime = youtput / 2;
FlatStructuringElement se = new FlatStructuringElement(youtput,
xoutput, new Point(xoutput / 2, youtput / 2));
se.fill(false);
for (int x = 0; x < this.cols; x++)
for (int y = 0; y < this.rows; y++) {
int xprime = (int) Math.round((x - xm) * atcos - (y - ym)
* atsin + xmprime);
int yprime = (int) Math.round((x - xm) * atsin + (y - ym)
* atcos + ymprime);
if (xprime < 0) {
xprime = 0;
}
if (xprime >= xoutput) {
xprime = xoutput - 1;
}
if (yprime < 0) {
yprime = 0;
}
if (yprime >= youtput) {
yprime = youtput - 1;
}
se.setValue(yprime, xprime, this.getValue(y, x));
}
int centreX = (int) this.getCenter().getX();
int centreY = (int) this.getCenter().getY();
int centreXprime = (int) Math.round((centreX - xm) * atcos
- (centreY - ym) * atsin + xmprime);
int centreYprime = (int) Math.round((centreX - xm) * atsin
+ (centreY - ym) * atcos + ymprime);
if (centreXprime < 0) {
centreXprime = 0;
}
if (centreXprime >= xoutput) {
centreXprime = xoutput - 1;
}
if (centreYprime < 0) {
centreYprime = 0;
}
if (centreYprime >= youtput) {
centreYprime = youtput - 1;
}
se.setCenter(new Point(centreXprime, centreYprime));
return se;
}
public void print() {
for (int j = 0; j < this.rows; j++) {
for (int i = 0; i < this.cols; i++) {
if (this.centre.x == i && this.centre.y == j) {
System.out.print("+ ");
} else if (this.getValue(j, i)) {
System.out.print("0 ");
} else {
System.out.print(" ");
}
}
System.out.println();
}
}
/**
* If the centre of the SE is set (=true) then it must be placed first!
*
* @return an array of Points containing the coordinates of pixels set to
* true
*/
public Point[] getPoints() {
if (points != null)
return points;
int size = 0;
for (int i = 0; i < cols; i++)
for (int j = 0; j < rows; j++)
if (isValue(j, i) == true)
size++;
points = new Point[size];
int k = 0;
if (isValue(centre.y, centre.x) == true)
points[k++] = new Point(centre.y, centre.x);
// System.err.println(cols + " " + rows + " " + size);
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
if (isValue(j, i) == true && !(i == centre.x && j == centre.y))
points[k++] = new Point(j, i);
}
}
return points;
}
/**
* Dessine l'lment structurant sur une image
*
* @param im
* Image dans laquelle dessiner
* @param p
* Translation de l'lment structurant
*/
public void draw(Image im, Point p) {
draw(im, p.x, p.y);
}
/**
* Dessine l'lment structurant sur une image
*
* @param im
* Image dans laquelle dessiner
* @param x
* Translation de l'lment structurant en x
* @param y
* Translation de l'lment structurant en y
*/
public void draw(Image im, int x, int y) {
int cX = x - centre.x;
int cY = y - centre.x;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++) {
int valX = i + cX;
int valY = j + cY;
if (getValue(i, j) && valX >= 0 && valX < im.getXDim()
&& valY >= 0 && valY < im.getYDim())
im.setPixelXYBoolean(valX, valY, true);
}
}
}