BendingEnergyDescriptor.java

Go to the documentation of this file.
00001 package theba.descriptors;
00002 
00003 import java.awt.Point;
00004 import java.util.ArrayList;
00005 
00006 import theba.core.ImageFunctions;
00007 import theba.core.RegionDescriptor;
00008 import theba.core.RegionMask;
00009 
00010 
00011 public class BendingEnergyDescriptor implements RegionDescriptor {
00012 
00013         public double measure(short[] pixels, int width, int height) {
00014 
00015                 // Gaussian 1d-kernels for sigma = 3.0:
00016                 // standard gaussian
00017                 // final double[] d0xGaussian = {0.0807 , 0.1065 , 0.1258 , 0.1330,
00018                 // 0.1258, 0.1065, 0.0807};
00019                 // derivated 1 time
00020                 final double[] d1xGaussian = { 0.0269, 0.0237, 0.0140, 0, -0.0140,
00021                                 -0.0237, -0.0269 };
00022                 // derivated 2 times
00023                 final double[] d2xGaussian = { 0, -0.0066, -0.0124, -0.0148, -0.0124,
00024                                 -0.0066, 0 };
00025 
00026                 final int radius = 3;
00027 
00028                 ArrayList points = ImageFunctions.borderTrace(pixels, width, height);
00029                 if (points == null)
00030                         return -1; // return impossible value as error indication
00031 
00032                 int vectorLength = points.size() + 2 * radius;
00033                 double x[] = new double[vectorLength];
00034                 double y[] = new double[vectorLength];
00035 
00036                 Point p = (Point) points.get(0);
00037                 double xMin = p.x, yMin = p.y;
00038                 for (int k = 0; k < points.size(); k++) {
00039                         p = (Point) points.get(k);
00040                         x[k + radius] = p.x;
00041                         y[k + radius] = p.y;
00042 
00043                         if (p.x < xMin)
00044                                 xMin = p.x;
00045                         if (p.y < yMin)
00046                                 yMin = p.y;
00047 
00048                 }
00049 
00050                 // pad with real values to avoid hit by zeros
00051                 // get real values by wrap-around
00052                 for (int k = 0; k < radius; k++) {
00053                         x[k] = x[x.length - 2 * radius + k];
00054                         y[k] = y[x.length - 2 * radius + k];
00055                 }
00056                 for (int k = x.length - radius; k < x.length; k++) {
00057                         x[k] = x[k - x.length + 2 * radius];
00058                         y[k] = y[k - x.length + 2 * radius];
00059                 }
00060 
00061                 // Make translation invariant
00062                 for (int k = 0; k < x.length; k++) {
00063                         x[k] -= xMin;
00064                         y[k] -= yMin;
00065                 }
00066 
00067                 double[] dx = new double[vectorLength];
00068                 double[] dy = new double[vectorLength];
00069                 double[] dxx = new double[vectorLength];
00070                 double[] dyy = new double[vectorLength];
00071 
00072                 // Calculate df/dx, df/dy, df/dxx, df/dyy by convolution
00073                 for (int k = radius; k < vectorLength - radius; k++) {
00074 
00075                         for (int m = -radius; m <= radius; m++) {
00076                                 dx[k] += x[k + m] * d1xGaussian[m + radius];
00077                                 dxx[k] += x[k + m] * d2xGaussian[m + radius];
00078 
00079                                 dy[k] += y[k + m] * d1xGaussian[m + radius];
00080                                 dyy[k] += y[k + m] * d2xGaussian[m + radius];
00081                         }
00082                 }
00083 
00084                 double bendingEnergySum = 0;
00085                 for (int k = radius; k < vectorLength - radius; k++) {
00086                         double factor = dx[k] * dyy[k] - dy[k] * dxx[k];
00087                         double dividend = Math.pow(dx[k] * dx[k] + dy[k] * dy[k], 1.5);
00088                         // guard against small dividend, sign doesn't matter
00089                         if (Math.abs(dividend) < 0.001) {
00090                                 dividend = 0.001;
00091                         }
00092                         bendingEnergySum += (factor / dividend) * (factor / dividend);
00093 
00094                 }
00095                 // Normalize results by dividing by number of points of border and
00096                 // return
00097                 return 100 * bendingEnergySum
00098                                 / (points.size() * points.size() * points.size());
00099         }
00100 
00101         public String getName() {
00102                 return "Bending energy";
00103         }
00104 
00105         public Object measure(RegionMask vmask) {
00106                 short[] mask = new short[vmask.getWidth() * vmask.getHeight()];
00107                 for (int x = 0; x < vmask.getWidth(); x++)
00108                         for (int y = 0; y < vmask.getHeight(); y++)
00109                                 if (vmask.isSet(x, y, 0))
00110                                         mask[x + y * vmask.getWidth()] = 1;
00111                 return measure(mask, vmask.getWidth(), vmask.getHeight());
00112         }
00113 
00114         public String getAbout() {
00115                 // TODO Auto-generated method stub
00116                 return null;
00117         }
00118 
00119         public boolean does3D() {
00120                 // TODO Auto-generated method stub
00121                 return false;
00122         }
00123 
00124         public boolean isNumeric() {
00125                 return true;
00126         }
00127 
00128 }

Generated on Fri Nov 13 08:57:07 2009 for Theba by  doxygen 1.6.1