/* * 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.features; import de.lmu.ifi.dbs.jfeaturelib.LibProperties; import de.lmu.ifi.dbs.jfeaturelib.Progress; import de.lmu.ifi.dbs.utilities.Arrays2; import ij.process.ImageProcessor; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; /** * This abstract class provides some convenient base functionalities for feature descriptors like the getter for the * data (including null check) and the propery change support. * * @author Franz */ public abstract class AbstractFeatureDescriptor implements FeatureDescriptor { /** * holds the most recent progress event that was fired using the * {@link #firePropertyChange(de.lmu.dbs.jfeaturelib.Progress)} method. */ private Progress previous = null; /** * Property change support that can be used by the implementing class to inform listeners about updates. */ protected final PropertyChangeSupport pcs = new PropertyChangeSupport(this); /** * The data arrays which hold the calculated features. * * Most of the descriptors will only return a single array. Yet there are some descriptors like Sift which return a * bag of features. */ private List<double[]> data = new ArrayList<>(1); /** * Stores the mask of the passed image processor or NULL if the image processor did not have a mask applied. * * Pixels outside the mask have a value of zero. */ private ImageProcessor mask = null; /** * Returns a reference to the data calculated by the according descriptor. * * The list will most likely just containa single double array holding the computed values. In cases where a * descriptor computes mutliple features (for example SIFT, where a vector is calculated for each point of * interest), the list will contain several double arrays. * * @return list of feature vectors. */ @Override public List<double[]> getFeatures() { return data; } /** * Adds a Property change listener for this feature vector. * * During the computation of the descriptor, at least 2 progress events should be fired (Start/End). * * @see Progress#START * @see Progress#END * @see Progress * @param listener */ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } /** * Adds the double array to the list. Keep in mind that the array is NOT copied but directly put into the list. * * @see #data */ protected void addData(double[] data) { this.data.add(data); } /** * Converts the given int array to double[] and adds this array to the list. * * @see #data */ protected void addData(int[] data) { this.data.add(Arrays2.convertToDouble(data)); } /** * Adds the double array list to the list of data arrays. Keep in mind that the array is NOT copied but directly put * into the list. * * @param data * @see #data */ protected void addData(List<double[]> data) { this.data.addAll(data); } /** * Propagates the given progress event using property change support. * * The old value of the firePropertyChange is the most recent progress event that was propagated by this method * (null in case of the first event). * * @param event */ protected void firePropertyChange(Progress event) { pcs.firePropertyChange(Progress.getName(), previous, event); previous = event; } @Override public void setProperties(LibProperties properties) throws IOException { } @Override public EnumSet<Supports> supports() { return DOES_ALL; } protected void startProgress() { pcs.firePropertyChange(Progress.getName(), null, Progress.START); } protected void endProgress() { pcs.firePropertyChange(Progress.getName(), null, Progress.END); } /** * Sets / stores the mask applied to the referenced image processor. * * @param ip the image processor from which the mask should be taken */ protected void setMask(ImageProcessor ip) { if (ip == null) { throw new NullPointerException("passed imageprocessor must not be null"); } this.mask = ip.getMask(); } /** * Check wether a pixel is inside a set mask. If no mask is applied, then the method always returns true. * * If a pixel is in the mask, this means that it should be processed. * * @param x * @param y * @return true if the pixel is in the mask and should thus be processed. */ protected boolean inMask(int x, int y) { return mask == null || mask.get(x, y) != 0; } /** * @return the current mask */ public ImageProcessor getMask() { return mask; } }