1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
/**
* basic 2D Snake
*
* @author Xavier Philippeau
*/
public class Snake {
private Image image = null;
private Channel force = null;
private Point[] snake = null;
public double alpha=0.8, beta=0.5, gamma=8.0;
public Snake(Image image, Point... points) {
this.image = image;
this.snake = points;
Channel gradient = new Gradient(3,1.0).filter(image);
this.force = new Chamfer(true,Chamfer.chamfer5).filter(gradient);
}
public void loop() {
while(step());
}
private boolean step() {
boolean moved=false;
// 3x3 neighborhood
double[][] econt = new double[3][3];
double[][] ecurv = new double[3][3];
double[][] eforc = new double[3][3];
// for each point of the snake
for(int i=0;i<snake.length;i++) {
Point prev = snake[(i+snake.length-1)%snake.length];
Point cur = snake[i];
Point next = snake[(i+1)%snake.length];
// compute local energies
double sum_econt=0, sum_ecurv=0, sum_eforc=0;
for(int dy=-1;dy<=1;dy++) {
for(int dx=-1;dx<=1;dx++) {
Point p = new Point( cur.x+dx, cur.y+dy );
econt[1+dx][1+dy]=continuity(prev,p,next);
ecurv[1+dx][1+dy]=curvature(prev,p,next);
eforc[1+dx][1+dy]=extforce(p);
// sum of matrix
sum_econt+=econt[1+dx][1+dy];
sum_ecurv+=ecurv[1+dx][1+dy];
sum_eforc+=eforc[1+dx][1+dy];
}
}
// normalize energies
for(int dy=-1;dy<=1;dy++) {
for(int dx=-1;dx<=1;dx++) {
if (sum_econt>0) econt[1+dx][1+dy]/=sum_econt;
if (sum_ecurv>0) ecurv[1+dx][1+dy]/=sum_ecurv;
if (sum_eforc>0) eforc[1+dx][1+dy]/=sum_eforc;
}
}
// find minimum total energy
double emin = Double.MAX_VALUE; int x=0,y=0;
for(int dy=-1;dy<=1;dy++) {
for(int dx=-1;dx<=1;dx++) {
double e = 0;
e+= alpha * econt[1+dx][1+dy];
e+= beta * ecurv[1+dx][1+dy];
e+= gamma * eforc[1+dx][1+dy];
if (e<emin) {
emin=e; x=cur.x+dx; y=cur.y+dy;
}
}
}
// boundary check
if (x<0) x=0;
if (x>=image.getWidth()) x=image.getWidth()-1;
if (y<0) y=0;
if (y>=image.getHeight()) y=image.getHeight()-1;
// the returned value
if (x!=cur.x || y!=cur.y) moved=true;
// move snake point
cur.x = x;
cur.y = y;
}
return moved;
}
private double continuity(Point prev, Point p, Point next) {
int ux = p.x-prev.x;
int uy = p.y-prev.y;
double un = ux*ux+uy*uy;
int vx = next.x-p.x;
int vy = next.y-p.y;
double vn = vx*vx+vy*vy;
int dx = next.x-prev.x;
int dy = next.y-prev.y;
double dn = dx*dx+dy*dy;
return ((un+vn)-dn)/dn;
}
private double curvature(Point prev, Point p, Point next) {
int ux = prev.x-p.x;
int uy = prev.y-p.y;
double un = ux*ux+uy*uy;
int vx = next.x-p.x;
int vy = next.y-p.y;
double vn = vx*vx+vy*vy;
double cx = ux + vx;
double cy = uy + vy;
return (cx*cx+cy*cy)/(un*vn);
}
private double extforce(Point p) {
return this.force.getValue(p.x, p.y);
}
} |
Partager