Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.alibaba.simpleimage.analyze.harissurf;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
 
结合了Harris Corner Detector 以及 Surf Haarwave Descriptor 削弱了对尺度缩放的抵抗性,降低特征维度从128到64,增加特征提取的效率

Author(s):
hui.xueh
 
 public class HarrisSurf {
 
     private IntegralImage           mIntegralImage;
     private double                  sigma;
     private double                  k;
     int                             spacing;
     private int[][]                 input;
     private int                     width;
     private int                     height;
     private static float[][]        guassian81_25;
 
     static {
         int radius = 13;
          = new float[radius][radius];
         for (int j = 0; j < radiusj++)
             for (int i = 0; i < radiusi++)
                 [i][j] = (floatgaussian(ij, 2.5F);
     }
 
     public List<SURFInterestPointgetInterestPoints() {
         return ;
     }
 
     public HarrisSurf(BufferedImage image){
         this(image, 1.2, 0.06, 4);
     }

    

Parameters:
image ,输入图像
sigma ,高斯平滑的参数
k ,Harris Corner计算的参数
spacing ,邻近点的最小距离,该范围内只取一个强度最大的特征点
 
     public HarrisSurf(BufferedImage imagedouble sigmadouble kint spacing){
         this. = sigma;
         this. = k;
         this. = spacing;
 
          = image.getWidth();
          = image.getHeight();
          = new int[][];
         for (int i = 0; i <  - 1; i++) {
             for (int j = 0; j <  - 1; j++) {
                 [i][j] = rgb2gray(image.getRGB(ij));
             }
         }
          = new IntegralImage(image);
          = new ArrayList<SURFInterestPoint>();
     }
 
     public static void joinsFilter(Map<SURFInterestPointSURFInterestPointmatchMap) {
         Iterator<Entry<SURFInterestPointSURFInterestPoint>> iter = matchMap.entrySet().iterator();
         Map<SURFInterestPointIntegermap = new HashMap<SURFInterestPointInteger>();
         while (iter.hasNext()) {
             Entry<SURFInterestPointSURFInterestPointe = iter.next();
             Integer kp1V = map.get(e.getKey());
             int lI = (kp1V == null) ? 0 : (intkp1V;
             map.put(e.getKey(), lI + 1);
             Integer kp2V = map.get(e.getValue());
             int rI = (kp2V == null) ? 0 : (intkp2V;
             map.put(e.getValue(), rI + 1);
         }
         iter = matchMap.entrySet().iterator();
         while (iter.hasNext()) {
             Entry<SURFInterestPointSURFInterestPointe = iter.next();
             Integer kp1V = map.get(e.getKey());
             Integer kp2V = map.get(e.getValue());
             if (kp1V > 1 || kp2V > 1) iter.remove();
         }
     }

    
给点一组匹配的特征点对,使用几何位置过滤其中不符合的点对,目前的策略包括: 1、特征主方向差别 2、斜率一致性

Parameters:
matchMap
 
     public static void geometricFilter(Map<SURFInterestPointSURFInterestPointmatchMapint wint h) {
         if (matchMap.size() <= 1) return;
         int arcStep = ModifiableConst.getSolpeArcStep();
        int[] ms = new int[90 / arcStep + 1]; // 用数据的索引拂过每个度数的key,不使用map来保存,性能优化
        Iterator<Entry<SURFInterestPointSURFInterestPoint>> iter = matchMap.entrySet().iterator();
        // Map<Long, Integer> voteMap = new HashMap<Long, Integer>();
        int max_vote_count = 0;
        long max_vote = 0;
        while (iter.hasNext()) {
            Entry<SURFInterestPointSURFInterestPointentry = iter.next();
            SURFInterestPoint fromPoint = entry.getKey();
            SURFInterestPoint toPoint = entry.getValue();
            if (Math.abs(toPoint.getOrientation() - fromPoint.getOrientation()) > 0.1) {
                iter.remove();
            } else {
                double r = Math.atan((toPoint.getY() + h - fromPoint.getY()) / (toPoint.getX() + w - fromPoint.getX()))
                           * 360 / (2 * .);
                if (r < 0) r += 90;
                int idx = (intr / arcStep// 取整
                ms[idx] = ms[idx] + 1;
                if (ms[idx] > max_vote_count) {
                    max_vote_count = ms[idx];
                    max_vote = idx;
                }
            }
        }
        iter = matchMap.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<SURFInterestPointSURFInterestPointentry = iter.next();
            SURFInterestPoint fromPoint = entry.getKey();
            SURFInterestPoint toPoint = entry.getValue();
            double r = Math.atan((toPoint.getY() + h - fromPoint.getY()) / (toPoint.getX() + w - fromPoint.getX()))
                       * 360 / (2 * .);
            if (r < 0) r += 90;
            int idx = (intr / arcStep// 取整
            if (idx != max_voteiter.remove();
        }
    }

    
特征检测,使用harris corner detector

Returns:
    public List<CornerdetectInterestPoints() {
        HarrisFast hf = new HarrisFast();
        hf.filter();
        return hf.corners;
    }

    
特征描述,在已输入的角点上提取surf descriptor

Parameters:
corners
    public void getDescriptions(List<Cornercornersboolean brootsift) {
        for (Corner c : corners) {
            SURFInterestPoint sp = new SURFInterestPoint(c.getX(), c.getY(), 1, (intc.getH());
            getOrientation(sp);
            // System.out.println(sp.getOrientation());
            getMDescriptor(sptruebrootsift);
            // System.out.println(sp.getDescriptorString());
            .add(sp);
        }
    }

    
灰度化

Parameters:
srgb
Returns:
    private static int rgb2gray(int srgb) {
        int r = (srgb >> 16) & 0xFF;
        int g = (srgb >> 8) & 0xFF;
        int b = srgb & 0xFF;
        return (int) (0.299 * r + 0.587 * g + 0.114 * b);
    }

    
计算主方向

Parameters:
input
    private void getOrientation(SURFInterestPoint input) {
        double gauss;
        float scale = input.getScale();
        int s = (int) Math.round(scale);
        int r = (int) Math.round(input.getY());
        int c = (int) Math.round(input.getX());
        List<DoublexHaarResponses = new ArrayList<Double>();
        List<DoubleyHaarResponses = new ArrayList<Double>();
        List<Doubleangles = new ArrayList<Double>();
        // calculate haar responses for points within radius of 6*scale
        for (int i = -6; i <= 6; ++i) {
            for (int j = -6; j <= 6; ++j) {
                if (i * i + j * j < 36) {
                    gauss = .[Math.abs(i)][Math.abs(j)];
                    double xHaarResponse = gauss * haarX(r + j * sc + i * s, 4 * s);
                    double yHaarResponse = gauss * haarY(r + j * sc + i * s, 4 * s);
                    xHaarResponses.add(xHaarResponse);
                    yHaarResponses.add(yHaarResponse);
                    angles.add(getAngle(xHaarResponseyHaarResponse));
                }
            }
        }
        // calculate the dominant direction
        float sumX = 0, sumY = 0;
        float ang1ang2ang;
        float max = 0;
        float orientation = 0;
        // loop slides pi/3 window around feature point
        for (ang1 = 0; ang1 < 2 * .ang1 += 0.15f) {
            ang2 = (float) (ang1 + . / 3.0f > 2 * . ? ang1 - 5.0f * . / 3.0f : ang1 + . / 3.0f);
            sumX = sumY = 0;
            for (int k = 0; k < angles.size(); k++) {
                ang = angles.get(k).floatValue();
                if (ang1 < ang2 && ang1 < ang && ang < ang2) {
                    sumX += xHaarResponses.get(k).floatValue();
                    sumY += yHaarResponses.get(k).floatValue();
                } else if (ang2 < ang1 && ((ang > 0 && ang < ang2) || (ang > ang1 && ang < 2 * .))) {
                    sumX += xHaarResponses.get(k).floatValue();
                    sumY += yHaarResponses.get(k).floatValue();
                }
            }
            if (sumX * sumX + sumY * sumY > max) {
                max = sumX * sumX + sumY * sumY;
                orientation = (floatgetAngle(sumXsumY);
            }
        }
        input.setOrientation(orientation);
    }
    private float haarX(int rowint columnint s) {
        return ImageTransformUtils.BoxIntegral(row - s / 2, columnss / 2) - 1
               * ImageTransformUtils.BoxIntegral(row - s / 2, column - s / 2, ss / 2);
    }
    private float haarY(int rowint columnint s) {
        return ImageTransformUtils.BoxIntegral(rowcolumn - s / 2, s / 2, s) - 1
               * ImageTransformUtils.BoxIntegral(row - s / 2, column - s / 2, s / 2, s);
    }
    private static double getAngle(double xHaarResponsedouble yHaarResponse) {
        if (xHaarResponse >= 0 && yHaarResponse >= 0) return Math.atan(yHaarResponse / xHaarResponse);
        if (xHaarResponse < 0 && yHaarResponse >= 0) return . - Math.atan(-yHaarResponse / xHaarResponse);
        if (xHaarResponse < 0 && yHaarResponse < 0) return . + Math.atan(yHaarResponse / xHaarResponse);
        if (xHaarResponse >= 0 && yHaarResponse < 0) return 2 * . - Math.atan(-yHaarResponse / xHaarResponse);
        return 0;
    }

    
获取描述子

Parameters:
point
upright ,是否采用方向归一化,影响到对旋转的抵抗性
    private void getMDescriptor(SURFInterestPoint pointboolean uprightboolean brootsift) {
        int yxcount = 0;
        int sample_xsample_y;
        double scaledxdymdxmdy;//, co = 1F, si = 0F;
        float desc[] = new float[64];
        double gauss_s1 = 0.0D, gauss_s2 = 0.0D;//, xs = 0.0D, ys = 0.0D;
        double rx = 0.0D, ry = 0.0D, rrx = 0.0D, rry = 0.0D, len = 0.0D;
        int i = 0,  j = 0; //ix = 0,jx = 0;
        float cx = -0.5f, cy = 0.0f; // Subregion centers for the 4x4 gaussian
                                     // weighting
        scale = point.getScale();
        x = Math.round(point.getX());
        y = Math.round(point.getY());
        // System.out.println("x = " + point.getX() + ", y = " + point.getY());
        // System.out.println("x = " + x + ", y = " + y);
        // if (!upright) {
        // co = Math.cos(point.getOrientation());
        // si = Math.sin(point.getOrientation());
        // }
        // System.out.println("co = " + co + ", sin = " + si);
        i = -8;
        // Calculate descriptor for this interest point
        // Area of size 24 s x 24 s
        // ***********************************************
        while (i < 12) {
            j = -8;
            i = i - 4;
            cx += 1.0F;
            cy = -0.5F;
            while (j < 12) {
                dx = dy = mdx = mdy = 0.0F;
                cy += 1.0F;
                j = j - 4;
//                ix = i + 5;
//                jx = j + 5;
                // if (!upright) {
                // xs = Math.round(x + (-jx * scale * si + ix * scale * co));
                // ys = Math.round(y + (jx * scale * co + ix * scale * si));
                // } else {
                // xs = x;
                // ys = y;
                // }
                for (int k = ik < i + 9; ++k) {
                    for (int l = jl < j + 9; ++l) {
                        // Get coords of sample point on the rotated axis
                        // sample_x = (int)Math.round(x + (-1D * l * scale * si
                        // + k * scale * co));
                        // sample_y = (int)Math.round(y + ( l * scale * co + k *
                        // scale * si));
                        sample_x = x + k;
                        sample_y = y + l;
                        // System.out.println(k + ", " + l);
                        // Get the gaussian weighted x and y responses
                        // gauss_s1 = gaussian(xs - sample_x, ys - sample_y,
                        // 2.5F * scale);
                        gauss_s1 = [Math.abs(k)][Math.abs(l)];
                        rx = haarX(sample_ysample_x, (int) (2 * Math.round(scale)));
                        ry = haarY(sample_ysample_x, (int) (2 * Math.round(scale)));
                        // Get the gaussian weighted x and y responses on
                        // rotated axis
                        // rrx = gauss_s1 * (-rx*si + ry*co);
                        // rry = gauss_s1 * (rx*co + ry*si);
                        rrx = gauss_s1 * (ry);
                        rry = gauss_s1 * (rx);
                        dx += rrx;
                        dy += rry;
                        mdx += Math.abs(rrx);
                        mdy += Math.abs(rry);
                    }
                }
                // Add the values to the descriptor vector
                gauss_s2 = gaussian(cx - 2.0f, cy - 2.0f, 1.5f);
                // Casting from a double to a float, might be a terrible idea
                // but doubles are expensive
                desc[count++] = (float) (dx * gauss_s2);
                desc[count++] = (float) (dy * gauss_s2);
                desc[count++] = (float) (mdx * gauss_s2);
                desc[count++] = (float) (mdy * gauss_s2);
                // Accumulate length for vector normalisation
                len += (dx * dx + dy * dy + mdx * mdx + mdy * mdy) * (gauss_s2 * gauss_s2);
                j += 9;
            }
            i += 9;
        }
        len = Math.sqrt(len);
        for (i = 0; i < desc.lengthi++) {
            desc[i] /= len;
        }
        // RootSift from [1]
        // [1] R. Arandjelović, A. Zisserman.
        // Three things everyone should know to improve object retrieval. CVPR2012.
        // -> rootsift= sqrt( sift / sum(sift) );
        if (brootsift) {
            float sum = 0.0f;
            for (float f : desc)
                sum += Math.abs(f);
            for (i = 0; i < desc.lengthi++) {
                if (desc[i] < 0) desc[i] = (float) -Math.sqrt(-desc[i] / sum);
                else desc[i] = (float) Math.sqrt(desc[i] / sum);
            }
        }
        point.setDescriptor(desc);
        // for ( double v : desc ){
        // System.out.printf("%.7f",v);
        // System.out.print(",");
        // }
        // System.out.println();
    }

    
采用高斯分布作为距离的权重因子

Parameters:
x
y
sig
Returns:
    private static double gaussian(double xdouble ydouble sig) {
        return (1.0f / (2.0f * . * sig * sig)) * Math.exp(-(x * x + y * y) / (2.0f * sig * sig));
    }
                                                                  List<SURFInterestPointdest) {
        for (SURFInterestPoint sp : src) {
            double min_dist = .;
            SURFInterestPoint min_sp = null;
            for (SURFInterestPoint sp2 : dest) {
                double distance = sp.getDistance(sp2);
                if (distance < min_dist) {
                    min_dist = distance;
                    min_sp = sp2;
                }
            }
            matchMap.put(spmin_sp);
        }
        return matchMap;
    }
    // The Integer-normalized version of the globalKeypoints.
        if ( != nullreturn ();
        if (this. == nullthrow (new IllegalArgumentException("No interestPoints generated yet."));
        for (SURFInterestPoint sp : ) {
            .add(new SURFInterestPointN(sp));
        }
        return ();
    }
New to GrepCode? Check out our FAQ X