001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.image.feature.local.detector.pyramid;
031
032import org.openimaj.citation.annotation.Reference;
033import org.openimaj.citation.annotation.ReferenceType;
034import org.openimaj.citation.annotation.References;
035import org.openimaj.image.FImage;
036import org.openimaj.image.analysis.pyramid.gaussian.GaussianOctave;
037
038/**
039 * <p>
040 * A basic concrete implementation of an {@link AbstractOctaveExtremaFinder}
041 * that searches for local extrema in scale space. If detected extrema pass a
042 * series of tests (namely those described in
043 * {@link AbstractOctaveExtremaFinder}) and a final test that tests the absolute
044 * value of the interest point pixel against a threshold, then the listener
045 * object will be informed that a point has been detected.
046 * </p>
047 * 
048 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
049 * 
050 */
051@References(references = {
052                @Reference(
053                                type = ReferenceType.Article,
054                                author = { "David Lowe" },
055                                title = "Distinctive image features from scale-invariant keypoints",
056                                year = "2004",
057                                journal = "IJCV",
058                                pages = { "91", "110" },
059                                month = "January",
060                                number = "2",
061                                volume = "60"),
062                @Reference(
063                                type = ReferenceType.Inproceedings,
064                                author = { "David Lowe" },
065                                title = "Object recognition from local scale-invariant features",
066                                year = "1999",
067                                booktitle = "Proc. of the International Conference on Computer Vision {ICCV}",
068                                pages = { "1150", "1157" }
069                )
070})
071public class BasicOctaveExtremaFinder extends AbstractOctaveExtremaFinder<GaussianOctave<FImage>> {
072        /**
073         * The default threshold for the magnitude of interest points
074         */
075        public static final float DEFAULT_MAGNITUDE_THRESHOLD = 0.04f; // Lowe's
076                                                                                                                                        // IJCV
077                                                                                                                                        // suggests
078                                                                                                                                        // 0.03,
079                                                                                                                                        // but the
080                                                                                                                                        // open SIFT
081                                                                                                                                        // implementation
082                                                                                                                                        // uses 0.04
083
084        // Threshold on the magnitude of detected points (Lowe IJCV, p.11)
085        protected float magnitudeThreshold = DEFAULT_MAGNITUDE_THRESHOLD;
086
087        protected float scales;
088        protected float normMagnitudeScales;
089
090        /**
091         * Default constructor using {@link #DEFAULT_MAGNITUDE_THRESHOLD} for the
092         * magnitude threshold and {@link #DEFAULT_EIGENVALUE_RATIO} for the
093         * Eigenvalue ratio threshold.
094         */
095        public BasicOctaveExtremaFinder() {
096        }
097
098        /**
099         * Construct with the given magnitude threshold and
100         * {@link #DEFAULT_EIGENVALUE_RATIO} for the Eigenvalue ratio threshold.
101         * 
102         * @param magnitudeThreshold
103         *            the magnitude threshold
104         */
105        public BasicOctaveExtremaFinder(float magnitudeThreshold) {
106                this(magnitudeThreshold, DEFAULT_EIGENVALUE_RATIO);
107        }
108
109        /**
110         * Construct with the given magnitude and Eigenvalue thresholds
111         * 
112         * @param magnitudeThreshold
113         *            the magnitude threshold
114         * @param eigenvalueRatio
115         *            the Eigenvalue threshold
116         */
117        public BasicOctaveExtremaFinder(float magnitudeThreshold, float eigenvalueRatio) {
118                super(eigenvalueRatio);
119                this.magnitudeThreshold = magnitudeThreshold;
120        }
121
122        @Override
123        protected void beforeProcess(GaussianOctave<FImage> octave) {
124                scales = octave.options.getScales();
125
126                // the magnitude threshold must be adjusted based on the number of
127                // scales,
128                // as more scales will result in smaller differences between scales
129                normMagnitudeScales = magnitudeThreshold / octave.options.getScales();
130        }
131
132        @Override
133        protected boolean firstCheck(float val, int x, int y, int s, FImage[] dogs) {
134                // perform magnitude check
135                if (Math.abs(dogs[s].pixels[y][x]) > normMagnitudeScales) {
136                        return true;
137                }
138                return false;
139        }
140
141        @Override
142        protected void processExtrema(FImage[] dogs, int s, int x, int y, float octSize) {
143                // calculate the actual scale within the octave
144                final float octaveScale = octave.options.getInitialSigma() * (float) Math.pow(2.0, s / scales);
145
146                // fire the listener
147                if (listener != null)
148                        listener.foundInterestPoint(this, x, y, octaveScale);
149        }
150}