/* * This file is part of the JFeatureLib project: https://github.com/locked-fg/JFeatureLib * JFeatureLib is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * JFeatureLib is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JFeatureLib; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * You are kindly asked to refer to the papers of the according authors which * should be mentioned in the Javadocs of the respective classes as well as the * JFeatureLib project itself. * * Hints how to cite the projects can be found at * https://github.com/locked-fg/JFeatureLib/wiki/Citation */ package de.lmu.ifi.dbs.jfeaturelib.utils; import de.lmu.ifi.dbs.jfeaturelib.ImagePoint; import ij.plugin.filter.GaussianBlur; import ij.process.ImageProcessor; import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; /** * Gaussian Blur where sigma is modified according to spacial position to the * "query point". * * Can be used as a component for geometric blur. Geom.blur first separates the * input image into 4 channels of half-wave rectified responses from oriented * edge filters. * * The idea was proposed by Alexander Berg: http://acberg.com/gb.html * * Relevant papers: Shape Matching and Object Recognition using Low Distortion * Correspondence Alexander C. Berg, Tamara L. Berg, Jitendra Malik IEEE * Computer Vision and Pattern Recognition (CVPR) 2005 (Presents a descriptor * based on geometric blur and applies this to object recognition.) * * Geometric Blur for Template Matching Alexander C. Berg, Jitendra Malik * Computer Vision and Pattern Recognition (CVPR) 2001, Hawaii, pp I.607-614 * (The original geometric blur paper concentrating on template matching and * localization.) * * Shape Matching and Object Recognition Alexander C. Berg Ph.D. Thesis, * Computer Science Division, U.C. Berkeley, December 2005 (Presents more detail * on the motivation for geometric blur, study of corresponding image patches, * etc.) * * @author Graf */ public class GeometricBlur { private final Distance distance = new DistanceL2(); private ImageProcessor ip = null; private double sigma = 5; private int blursteps = 20; private List<ImageProcessor> myStack = new ArrayList<>(); public GeometricBlur() { } /** * @param ip image processor of source image * @param sig maximum sigma of gauss blur * @param steps how many slices of images (with differing sigma) should be * created. */ public GeometricBlur(ImageProcessor ip, double sig, int steps) { this.sigma = sig; this.blursteps = steps; this.ip = ip; update(); } /** * @param out write blurred image into this image processor * @param center point in the source image being the center of the query */ public void paintInto(final ImageProcessor out, final ImagePoint center) { if (out == null) { throw new NullPointerException("ImageProcessor must not be null"); } int ow = out.getWidth(); int oh = out.getHeight(); ImagePoint p = new ImagePoint(); Rectangle bound = new Rectangle(ip.getWidth(), ip.getHeight()); int offsetX = (int) (center.x - ow / 2d); int offsetY = (int) (center.y - oh / 2d); for (int x = 0; x < ow; x++) { for (int y = 0; y < oh; y++) { // pixel coords of window in bigger source image p.x = offsetX + x; p.y = offsetY + y; if (bound.contains(p.x, p.y)) { out.putPixel(x, y, getPixel(p, center)); } } } } /** * Returns the spacially blurred pixel value at the point q, assuming that * center is the source of the blur. * * @param q pixel coordinate that should be retrieved * @param center the source of the blur * @return pixel value from {@link ImageProcessor#getPixel(int, int)} */ public int getPixel(ImagePoint q, ImagePoint center) { return myStack.get(getSlice(q, center)).getPixel((int) q.x, (int) q.y); } /** * Returns the spacially blurred pixel value at the point q, assuming that * center is the source of the blur. * * @param q pixel coordante which should be retrieved * @param center the source of the blur * @return pixel value from {@link ImageProcessor#getPixelValue(int, int)} */ public float getPixelValue(ImagePoint q, ImagePoint center) { return myStack.get(getSlice(q, center)).getPixelValue((int) q.getX(), (int) q.getY()); } private int getSlice(ImagePoint q, ImagePoint center) { double dst = distance.distance(q, center); int slice = (int) dst; if (slice < 0) { slice = 0; } else if (slice > myStack.size() - 1) { slice = myStack.size() - 1; } return slice; } /** * create the geometric blur stack */ private void update() { myStack.clear(); if (ip == null) { return; } // 0 = unmodified myStack.add(ip.duplicate()); for (int i = 1; i <= blursteps; i++) { ImageProcessor blurred = ip.duplicate(); double tmpSigma = i * sigma / (1d * blursteps); GaussianBlur gb = new GaussianBlur(); gb.blurGaussian(blurred, tmpSigma, tmpSigma, 0.01); myStack.add(blurred); } } public ImageProcessor getIp() { return ip; } public void setIp(ImageProcessor ip) { this.ip = ip; update(); } public int getBlursteps() { return blursteps; } public void setBlursteps(int blursteps) { this.blursteps = blursteps; update(); } public double getSigma() { return sigma; } public void setSigma(double sigma) { this.sigma = sigma; update(); } }