1 /**
2 * Copyright (c) 2011, The University of Southampton and the individual contributors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * * Neither the name of the University of Southampton nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 package org.openimaj.image.analysis.pyramid.gaussian;
31
32 import org.openimaj.image.FImage;
33 import org.openimaj.image.Image;
34 import org.openimaj.image.analyser.ImageAnalyser;
35 import org.openimaj.image.analysis.pyramid.Pyramid;
36 import org.openimaj.image.processing.resize.ResizeProcessor;
37 import org.openimaj.image.processor.SinglebandImageProcessor;
38
39 /**
40 * A Gaussian image pyramid consisting of a stack of octaves where the image
41 * halves its size. The pyramid is of the style described in Lowe's SIFT paper.
42 *
43 * Octaves are processed by an OctaveProcessor as they are created if the
44 * processor is set in the options object.
45 *
46 * The pyramid will only hold onto its octaves if either the keepOctaves option
47 * is set to true, or if a PyramidProcessor is set in the options. The
48 * PyramidProcessor will called after all the octaves are created.
49 *
50 * Pyramids are Iterable for easy access to the octaves; however this will only
51 * work if the pyramid has already been populated with the octaves retained.
52 *
53 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
54 *
55 * @param <I>
56 * Type of underlying image
57 */
58 public class GaussianPyramid<I extends Image<?, I> & SinglebandImageProcessor.Processable<Float, FImage, I>>
59 extends
60 Pyramid<GaussianPyramidOptions<I>, GaussianOctave<I>, I>
61 implements
62 ImageAnalyser<I>, Iterable<GaussianOctave<I>>
63 {
64 /**
65 * Construct a Pyramid with the given options.
66 *
67 * @param options
68 * the options
69 */
70 public GaussianPyramid(GaussianPyramidOptions<I> options) {
71 super(options);
72 }
73
74 /*
75 * (non-Javadoc)
76 *
77 * @see
78 * org.openimaj.image.processing.pyramid.AbstractPyramid#process(org.openimaj
79 * .image.Image)
80 */
81 @Override
82 public void process(I img) {
83 if (img.getWidth() <= 1 || img.getHeight() <= 1)
84 throw new IllegalArgumentException("Image is too small");
85
86 // the octave image size: 1 means same as input, 0.5 is twice as big as
87 // input, 2 is half input, 4 is quarter input, etc
88 float octaveSize = 1.0f;
89
90 // if doubleInitialImage is set, then the initial image should be scaled
91 // to
92 // twice its original size and the
93 I image;
94 if (options.doubleInitialImage) {
95 image = ResizeProcessor.doubleSize(img);
96 octaveSize *= 0.5;
97 } else
98 image = img.clone();
99
100 // Lowe's IJCV paper (P.10) suggests that if you double the size of the
101 // initial image then it has a sigma of 1.0; if the image is not doubled
102 // the sigma is 0.5
103 final float currentSigma = (options.doubleInitialImage ? 1.0f : 0.5f);
104 if (options.initialSigma > currentSigma) {
105 // we now need to bring the starting image to a sigma of
106 // initialSigma
107 // in order to start building the pyramid (every octave starts at
108 // initialSigma sigmas).
109 final float sigma = (float) Math.sqrt(options.initialSigma * options.initialSigma - currentSigma
110 * currentSigma);
111 image.processInplace(this.options.createGaussianBlur(sigma));
112 }
113
114 // the minimum size image in the pyramid must be bigger than
115 // two pixels + whatever border is required by the options
116 // (on both sides).
117 final int minImageSize = 2 + (2 * options.getBorderPixels());
118
119 while (image.getHeight() > minImageSize && image.getWidth() > minImageSize) {
120 // construct empty octave
121 final GaussianOctave<I> currentOctave = new GaussianOctave<I>(this, octaveSize);
122
123 // populate the octave with images; once the octave
124 // is complete any OctaveProcessor specified in the
125 // options will be applied.
126 currentOctave.process(image);
127
128 // get the image with 2*sigma from the octave and
129 // half its size ready for the next octave
130 image = ResizeProcessor.halfSize(currentOctave.getNextOctaveImage());
131
132 octaveSize *= 2.0; // the size of the octave increases by a factor
133 // of two each iteration
134
135 // if the octaves array is not null we want to retain each octave.
136 if (octaves != null)
137 octaves.add(currentOctave);
138 }
139
140 // if a PyramidProcessor was specified in the options it should
141 // be applied now all the octaves are complete.
142 if (options.getPyramidProcessor() != null) {
143 options.getPyramidProcessor().process(this);
144 }
145 }
146 }