/* * 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.scale; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import com.alibaba.simpleimage.analyze.sift.ImagePixelArray; /** * 类GaussiianArray.java的实现描述:高斯模糊的主算法 * * @author axman 2013-6-27 下午4:33:27 */ public class GaussianArray { private static final Logger log = Logger.getLogger(GaussianArray.class); private static Map<Float, float[]> cachedMask = new HashMap<Float, float[]>(); static { float[] sigmaVal = { 1.5f, 1.2262735f, 1.5450078f, 1.9465879f, 2.452547f, 3.0900156f }; for (int i = 0; i < sigmaVal.length; i++) { float[] mask = makeMask(sigmaVal[i], 1 + 2 * ((int) (3.0f * sigmaVal[i]))); cachedMask.put(sigmaVal[i], mask); } } public float[] mask; public GaussianArray(float sigma){ if (cachedMask.containsKey(sigma)) { this.mask = cachedMask.get(sigma); } else { this.mask = makeMask(sigma, 1 + 2 * ((int) (3.0f * sigma))); log.info("remake mask,sigma = " + sigma); } } // 由于sigma和dim使用了常数,所以高期总卷积最终是固定的,不需要每次都计算出来,可以先计算好然后缓存起来。 public static float[] makeMask(float sigma, int dim) { // 卷积核必须是奇数,才能有一个明显的中心核: // * * * // *[*]* // * * * dim |= 1; // 保证奇数矩阵 float[] mask = new float[dim]; float sigma2sq = 2 * sigma * sigma; float normalizeFactor = 1.0f / ((float) Math.sqrt(2.0 * Math.PI) * sigma); for (int i = 0; i < dim; i++) { int relPos = i - mask.length / 2; float G = (relPos * relPos) / sigma2sq; G = (float) Math.exp(-G); G *= normalizeFactor; mask[i] = G; } return mask; } public ImagePixelArray convolve(ImagePixelArray map) { return Filter.convolve(map, this.mask); } private static class Filter { public enum Direction { VERTICAL, HORIZONTAL } public static ImagePixelArray convolve(ImagePixelArray img, float[] mask) { ImagePixelArray im1 = new ImagePixelArray(img.width, img.height); ImagePixelArray im2 = new ImagePixelArray(img.width, img.height); convolve1D(im1, mask, img, Direction.VERTICAL); convolve1D(im2, mask, im1, Direction.HORIZONTAL); return im2; } public static void convolve1D(ImagePixelArray dest, float[] mask, ImagePixelArray src, Direction dir) { int maxN; // outer loop max index int maxP; // inner loop mac index if (dir == Direction.VERTICAL) { maxN = src.width; maxP = src.height; } else if (dir == Direction.HORIZONTAL) { maxN = src.height; maxP = src.width; } else { throw new java.lang.IllegalArgumentException("invalid direction"); } for (int n = 0; n < maxN; n++) { for (int p = 0; p < maxP; p++) { float val = calculateConvolutionValue1D(src, mask, n, p, maxN, maxP, dir); if (dir == Direction.VERTICAL) dest.data[n + p * dest.width] = val; else dest.data[p + n * dest.width] = val; } } } private static float calculateConvolutionValue1D(ImagePixelArray src, float[] mask, int n, int p, int maxN, int maxP, Direction dir) { float sum = 0.0f; boolean isOut = false; float outBound = 0.0f; for (int i = 0; i < mask.length; i++) { int curAbsP = i - (mask.length / 2) + p; if (curAbsP < 0 || curAbsP >= maxP) { isOut = true; outBound += mask[i]; continue; } if (dir == Direction.VERTICAL) sum += (mask[i] * src.data[curAbsP * src.width + n]); else sum += mask[i] * src.data[n * src.width + curAbsP]; } if (isOut) sum *= 1.0 / (1.0 - outBound); return sum; } } }