/* * Copyright 2013 Alibaba.com All right reserved. This software is the * confidential and proprietary information of Alibaba.com ("Confidential * Information"). You shall not disclose such Confidential Information and shall * use it only in accordance with the terms of the license agreement you entered * into with Alibaba.com. */ package com.alibaba.simpleimage.analyze.sift; import java.util.ArrayList; import java.util.List; import com.alibaba.simpleimage.analyze.sift.scale.FeaturePoint; import com.alibaba.simpleimage.analyze.sift.scale.GaussianArray; import com.alibaba.simpleimage.analyze.sift.scale.KDFeaturePoint; import com.alibaba.simpleimage.analyze.sift.scale.OctaveSpace; import com.alibaba.simpleimage.analyze.sift.scale.Pyramid; import com.alibaba.simpleimage.analyze.sift.scale.ScalePeak; /** * 类SIFT.java的实现描述:面向用户的主操作接口 * * @author axman 2013-6-28 上午10:15:45 */ public class SIFT { // 以下常数均是论文中推荐的参数值 float preprocSigma = 1.5f; // 用于处理被double后的图像预处理的模糊因子 float octaveSigma = 1.6f; // 用于处理每个8度空间图像的模糊因子 int minimumRequiredPixelsize = 32; // 高斯金字塔中缩小时最小的尺寸 int scaleSpaceLevels = 3; // 每个8度空间需要获取极值点的差分图层,加上用于比较的上下层至少要有5个差分图像,所以至少要有6个高斯模糊图象。 float dogThresh = 0.0075f; // 在差分图象上的极致点值最小值,防止大片的模糊后的点被选中,这个值越小选中的点越多。 float dValueLowThresh = 0.008f; // 和周围点比较的差值,这个差值是经过导数运算的差值,不是直接比较的。论文中建议为0.03(page // 11),但获取的点数太少,这里修改为0.008 float maximumEdgeRatio = 20.0f; // 非角点的过虑比 float scaleAdjustThresh = 0.50f; // 尺度空间的精确点和真实图象上的离散点在投谢时需要调整,这个是最大调整范围,超这个值就可能是下一个点。 float peakRelThresh = 0.8f; // int relocationMaximum = 4; public int detectFeatures(ImagePixelArray img) { return (detectFeaturesDownscaled(img, -1, 1.0f)); } /** * @param img * @param preProcessMark 图象预处理的标记,小于0,img需要double,大于0时,说明图象的长和宽要half到这个尺寸以下,等于0则不预处理 * @param startScale * @return */ public int detectFeaturesDownscaled(ImagePixelArray img, int preProcessMark, float startScale) { if (preProcessMark < 0) { img = img.doubled(); startScale *= 0.5; } else if (preProcessMark > 0) { while (img.width > preProcessMark || img.height > preProcessMark) { img = img.halved(); startScale *= 2.0; } } if (preprocSigma > 0.0) { GaussianArray gaussianPre = new GaussianArray(preprocSigma); img = gaussianPre.convolve(img); } Pyramid pyr = new Pyramid(); pyr.buildOctaves(img, startScale, scaleSpaceLevels, octaveSigma, minimumRequiredPixelsize); globalFeaturePoints = new ArrayList<FeaturePoint>(); // Generate featurePoints from each scalespace. for (int on = 0; on < pyr.octaves.size(); ++on) { OctaveSpace osp = pyr.octaves.get(on); ArrayList<ScalePeak> peaks = osp.findPeaks(dogThresh);// 寻找图片中的极值点 ArrayList<ScalePeak> peaksFilted = osp.filterAndLocalizePeaks(peaks, maximumEdgeRatio, dValueLowThresh, scaleAdjustThresh, relocationMaximum); // 先将要处理的图层上所有象素的梯度大小和方向计算出来 osp.pretreatMagnitudeAndDirectionImgs(); ArrayList<FeaturePoint> faturePoints = osp.makeFeaturePoints(peaksFilted, peakRelThresh, scaleSpaceLevels, octaveSigma); osp.clear(); globalFeaturePoints.addAll(faturePoints); } return (globalFeaturePoints.size()); } private List<FeaturePoint> globalFeaturePoints; private List<KDFeaturePoint> globalKDFeaturePoints; public List<KDFeaturePoint> getGlobalKDFeaturePoints() { if (globalKDFeaturePoints != null) return (globalKDFeaturePoints); if (globalFeaturePoints == null) throw (new IllegalArgumentException("No featurePoints generated yet.")); globalKDFeaturePoints = new ArrayList<KDFeaturePoint>(); for (FeaturePoint fp : globalFeaturePoints) { globalKDFeaturePoints.add(new KDFeaturePoint(fp)); } return globalKDFeaturePoints; } }