AvgCurvature.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 import theba.core.math.NonUniformInterpolation;
00010 
00011 
00012 public class AvgCurvature implements RegionDescriptor {
00013 
00014         public Object measure(RegionMask vmask) {
00015                 short[] mask = new short[vmask.getWidth() * vmask.getHeight()];
00016                 for (int x = 0; x < vmask.getWidth(); x++)
00017                         for (int y = 0; y < vmask.getHeight(); y++)
00018                                 if (vmask.isSet(x, y, 0))
00019                                         mask[x + y * vmask.getWidth()] = 1;
00020                 return measure(mask, vmask.getWidth(), vmask.getHeight());
00021         }
00022 
00023         public double measure(short[] pixels, int width, int height) {
00024                         
00025                 final double[] d1xGaussian = { 0.0269, 0.0237, 0.0140, 0, -0.0140,
00026                                 -0.0237, -0.0269 };
00027                 final double[] d2xGaussian = { 0, -0.0066, -0.0124, -0.0148, -0.0124,
00028                                 -0.0066, 0 };
00029 
00030                 final int radius = 3;
00031 
00032                 ArrayList points = ImageFunctions.borderTrace(pixels, width, height);
00033                 int[] chaincode = ImageFunctions.getChaincode(points);
00034                 double[] s = ImageFunctions.getArcLenghts(chaincode);
00035                 int vectorLength = points.size() + 2 * radius;
00036 
00037                 double x[] = new double[points.size()];
00038                 double y[] = new double[points.size()];
00039                 Point p = null;
00040                 for (int i = 0; i < points.size(); i++) {
00041                         p = (Point) points.get(i);
00042                         x[i] = p.x;
00043                         y[i] = p.y;
00044                 }
00045 
00046                 NonUniformInterpolation nx = new NonUniformInterpolation(s, x);
00047                 NonUniformInterpolation ny = new NonUniformInterpolation(s, y);
00048                 double step = s[s.length - 1] / s.length; // average distance between
00049                                                                                                         // points
00050 
00051                 double xi[] = new double[vectorLength];
00052                 double yi[] = new double[vectorLength];
00053                 double xMin = Double.MAX_VALUE;
00054                 double yMin = Double.MAX_VALUE;
00055                 double xMax = Double.MIN_VALUE;
00056                 double yMax = Double.MIN_VALUE;
00057                 double arcLength = 0;
00058                 for (int i = 0; i < s.length; i++) {
00059                         xi[i + radius] = nx.interpolate(arcLength);
00060                         yi[i + radius] = ny.interpolate(arcLength);
00061 
00062                         if (xi[i + radius] < xMin)
00063                                 xMin = xi[i + radius];
00064                         if (yi[i + radius] < yMin)
00065                                 yMin = yi[i + radius];
00066 
00067                         if (xi[i + radius] > xMax)
00068                                 xMax = xi[i + radius];
00069                         if (yi[i + radius] > yMax)
00070                                 yMax = yi[i + radius];
00071 
00072                         arcLength += step;
00073                 }
00074 
00075                 // for simplicity:
00076                 x = xi;
00077                 y = yi;
00078 
00079                 // pad with real values to avoid hit by zeros
00080                 // get real values by wrap-around
00081                 for (int k = 0; k < radius; k++) {
00082                         x[k] = x[x.length - 2 * radius + k];
00083                         y[k] = y[x.length - 2 * radius + k];
00084                 }
00085                 for (int k = x.length - radius; k < x.length; k++) {
00086                         x[k] = x[k - x.length + 2 * radius];
00087                         y[k] = y[k - x.length + 2 * radius];
00088                 }
00089 
00090                 // Make translation invariant
00091                 for (int k = 0; k < x.length; k++) {
00092                         x[k] -= xMin;
00093                         y[k] -= yMin;
00094                 }
00095 
00096                 double[] dx = new double[vectorLength];
00097                 double[] dy = new double[vectorLength];
00098                 double[] dxx = new double[vectorLength];
00099                 double[] dyy = new double[vectorLength];
00100                 // Calculate df/dx, df/dy, df/dxx, df/dyy by convolution
00101                 for (int k = radius; k < vectorLength - radius; k++) {
00102 
00103                         for (int m = -radius; m <= radius; m++) {
00104                                 dx[k] += x[k + m] * d1xGaussian[m + radius];
00105                                 dxx[k] += x[k + m] * d2xGaussian[m + radius];
00106 
00107                                 dy[k] += y[k + m] * d1xGaussian[m + radius];
00108                                 dyy[k] += y[k + m] * d2xGaussian[m + radius];
00109                         }
00110                 }
00111 
00112                 double curvatureSum = 0;
00113                 for (int k = radius; k < vectorLength - radius; k++) {
00114                         double factor = dx[k] * dyy[k] - dy[k] * dxx[k];
00115                         double dividend = Math.pow(dx[k] * dx[k] + dy[k] * dy[k], 1.5);
00116                         // guard against small dividend, its always positive
00117                         if (dividend < 0.001) {
00118                                 dividend = 0.001;
00119                         }
00120                         curvatureSum += Math.abs(factor / dividend);
00121 
00122                 }
00123                 // Normalize results by dividing by number of points of border and
00124                 // return
00125                 return curvatureSum / (points.size() * points.size());
00126 
00127         }
00128 
00129         public String getName() {
00130                 return "Average, scale-independent curvature";
00131         }
00132 
00133         public String getAbout() {
00134                 return "Returns the average, weighted curvature of a 4-connected 2D region";
00135         }
00136 
00137         public boolean does3D() {
00138                 return false;
00139         }
00140 
00141         public boolean isNumeric() {
00142                 return true;
00143         }
00144 
00145 }

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