Difference between revisions of "Example Image Pyramid"
(Updated for v0.3) |
m |
||
(13 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
<center> | <center> | ||
<gallery widths=300px heights=200px> | <gallery widths=300px heights=200px> | ||
Line 7: | Line 6: | ||
</center> | </center> | ||
[http://en.wikipedia.org/wiki/Pyramid_%28image_processing Image pyramids] are a common way to represent multi-resolution image information. | [http://en.wikipedia.org/wiki/Pyramid_%28image_processing Image pyramids] are a common way to represent multi-resolution image information. In an image pyramid, upper layers are lower resolution versions of the lower layers. BoofCV provides two types of image pyramids built in; PyramidDiscrete and PyramidFloat. PyramidDiscrete only allows the ratio between adjacent to have positive integer values, while PyramidFloat allows any arbitrary positive value. Discrete pyramids are much faster than float pyramids, but much more restrictive. | ||
Inside of BoofCV several algorithms make use of these two types of pyramids. | Inside of BoofCV several algorithms make use of these two types of pyramids. The KLT feature tracker uses a discrete pyramid and is the fastest feature tracker. Pyramid based scale space feature detectors use the float pyramid. | ||
Two code examples are provided below which demonstrate how to construct and visualize each type of pyramid. | Two code examples are provided below which demonstrate how to construct and visualize each type of pyramid. | ||
Example Code: | Example Code: | ||
* [https://github.com/lessthanoptimal/BoofCV/blob/ | * [https://github.com/lessthanoptimal/BoofCV/blob/v0.40/examples/src/main/java/boofcv/examples/imageprocessing/ExamplePyramidDiscrete.java ExamplePyramidDiscrete.java ] | ||
* [https://github.com/lessthanoptimal/BoofCV/blob/ | * [https://github.com/lessthanoptimal/BoofCV/blob/v0.40/examples/src/main/java/boofcv/examples/imageprocessing/ExamplePyramidFloat.java ExamplePyramidFloat.java ] | ||
Concepts: | Concepts: | ||
Line 21: | Line 20: | ||
* Discrete Vs. Float pyramids | * Discrete Vs. Float pyramids | ||
* Image scaling | * Image scaling | ||
= Image Pyramid Discrete = | = Image Pyramid Discrete = | ||
<syntaxhighlight lang="java"> | <syntaxhighlight lang="java"> | ||
/** | /** | ||
* Demonstrates how to construct and display a {@link PyramidDiscrete}. | * Demonstrates how to construct and display a {@link PyramidDiscrete}. Discrete pyramids require that | ||
* each level has a relative scale with an integer ratio and is updated by sparsely sub-sampling. | * each level has a relative scale with an integer ratio and is updated by sparsely sub-sampling. These | ||
* restrictions allows a very quick update across scale space. | * restrictions allows a very quick update across scale space. | ||
* | * | ||
* @author Peter Abeles | * @author Peter Abeles | ||
*/ | */ | ||
public class ExamplePyramidDiscrete<T extends | public class ExamplePyramidDiscrete<T extends ImageGray<T>> { | ||
// specifies the image type | // specifies the image type | ||
Class<T> imageType; | Class<T> imageType; | ||
public ExamplePyramidDiscrete(Class<T> imageType) { | public ExamplePyramidDiscrete( Class<T> imageType ) { | ||
this.imageType = imageType; | this.imageType = imageType; | ||
} | } | ||
Line 82: | Line 44: | ||
public void process( BufferedImage image ) { | public void process( BufferedImage image ) { | ||
T input = ConvertBufferedImage.convertFromSingle(image, null, imageType); | T input = ConvertBufferedImage.convertFromSingle(image, null, imageType); | ||
PyramidDiscrete<T> pyramid = FactoryPyramid.discreteGaussian( | |||
ConfigDiscreteLevels.levels(4), -1, 2, true, ImageType.single(imageType)); | |||
pyramid.process(input); | |||
var gui = new DiscretePyramidPanel<T>(); | |||
gui.setPyramid(pyramid); | gui.setPyramid(pyramid); | ||
gui.render(); | gui.render(); | ||
ShowImages.showWindow(gui,"Image Pyramid"); | ShowImages.showWindow(gui, "Image Pyramid"); | ||
// To get an image at any of the scales simply call this get function | // To get an image at any of the scales simply call this get function | ||
T imageAtScale = pyramid.getLayer(1); | T imageAtScale = pyramid.getLayer(1); | ||
ShowImages.showWindow(ConvertBufferedImage.convertTo(imageAtScale,null),"Image at layer 1"); | ShowImages.showWindow(ConvertBufferedImage.convertTo(imageAtScale, null, true), "Image at layer 1"); | ||
} | } | ||
public static void main( String[] args ) { | public static void main( String[] args ) { | ||
BufferedImage image = UtilImageIO. | BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample("standard/barbara.jpg")); | ||
var app = new ExamplePyramidDiscrete<>(GrayF32.class); | |||
// | // var app = new ExamplePyramidDiscrete<>(GrayU8.class); | ||
app.process(image); | app.process(image); | ||
} | } | ||
Line 114: | Line 76: | ||
<syntaxhighlight lang="java"> | <syntaxhighlight lang="java"> | ||
/** | /** | ||
* Demonstrates how to construct and display a {@link PyramidFloat}. | * Demonstrates how to construct and display a {@link PyramidFloat}. Float pyramids require only require | ||
* that each layer's scale be larger than the scale of the previous layer. Interpolation is used to allow | * that each layer's scale be larger than the scale of the previous layer. Interpolation is used to allow | ||
* sub-sampling at arbitrary scales. | * sub-sampling at arbitrary scales. All of this additional flexibility comes at the cost of speed | ||
* when compared to a {@link PyramidDiscrete}. | * when compared to a {@link PyramidDiscrete}. | ||
* | * | ||
* @author Peter Abeles | * @author Peter Abeles | ||
*/ | */ | ||
public class ExamplePyramidFloat<T extends | public class ExamplePyramidFloat<T extends ImageGray<T>> { | ||
// specifies the image type | // specifies the image type | ||
Line 127: | Line 89: | ||
// The pyramid data structure | // The pyramid data structure | ||
PyramidFloat<T> pyramid; | PyramidFloat<T> pyramid; | ||
public ExamplePyramidFloat(Class<T> imageType) { | public ExamplePyramidFloat( Class<T> imageType ) { | ||
this.imageType = imageType; | this.imageType = imageType; | ||
} | } | ||
Line 140: | Line 100: | ||
// Scale factory for each layer can be any floating point value which is larger than | // Scale factory for each layer can be any floating point value which is larger than | ||
// the previous layer's scale. | // the previous layer's scale. | ||
double[] scales = new double[]{1, 1.5, 2, 2.5, 3, 5, 8, 15}; | |||
// the amount of blur which is applied to each layer in the pyramid after the previous layer has been sampled | |||
// | double[] sigmas = new double[]{1, 1, 1, 1, 1, 1, 1, 1}; | ||
pyramid = FactoryPyramid.floatGaussian(scales, sigmas, imageType); | |||
} | } | ||
Line 152: | Line 111: | ||
public void process( BufferedImage image ) { | public void process( BufferedImage image ) { | ||
T input = ConvertBufferedImage.convertFromSingle(image, null, imageType); | T input = ConvertBufferedImage.convertFromSingle(image, null, imageType); | ||
pyramid.process(input); | |||
ImagePyramidPanel<T> gui = new ImagePyramidPanel< | ImagePyramidPanel<T> gui = new ImagePyramidPanel<>(); | ||
gui.set(pyramid, true); | gui.set(pyramid, true); | ||
gui.render(); | gui.render(); | ||
ShowImages.showWindow(gui,"Image Pyramid Float"); | ShowImages.showWindow(gui, "Image Pyramid Float"); | ||
// To get an image at any of the scales simply call this get function | // To get an image at any of the scales simply call this get function | ||
T imageAtScale = pyramid.getLayer(1); | T imageAtScale = pyramid.getLayer(1); | ||
ShowImages.showWindow(ConvertBufferedImage.convertTo(imageAtScale,null),"Image at layer 1"); | ShowImages.showWindow(ConvertBufferedImage.convertTo(imageAtScale, null, true), "Image at layer 1"); | ||
} | } | ||
public static void main( String[] args ) { | public static void main( String[] args ) { | ||
BufferedImage image = UtilImageIO. | BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample("standard/barbara.jpg")); | ||
var app = new ExamplePyramidFloat<>(GrayF32.class); | |||
// | // var app = new ExamplePyramidFloat<>(GrayU8.class); | ||
app.standard(); | app.standard(); |
Latest revision as of 15:11, 17 January 2022
Image pyramids are a common way to represent multi-resolution image information. In an image pyramid, upper layers are lower resolution versions of the lower layers. BoofCV provides two types of image pyramids built in; PyramidDiscrete and PyramidFloat. PyramidDiscrete only allows the ratio between adjacent to have positive integer values, while PyramidFloat allows any arbitrary positive value. Discrete pyramids are much faster than float pyramids, but much more restrictive.
Inside of BoofCV several algorithms make use of these two types of pyramids. The KLT feature tracker uses a discrete pyramid and is the fastest feature tracker. Pyramid based scale space feature detectors use the float pyramid.
Two code examples are provided below which demonstrate how to construct and visualize each type of pyramid.
Example Code:
Concepts:
- Multi-resolution image processing
- Discrete Vs. Float pyramids
- Image scaling
Image Pyramid Discrete
/**
* Demonstrates how to construct and display a {@link PyramidDiscrete}. Discrete pyramids require that
* each level has a relative scale with an integer ratio and is updated by sparsely sub-sampling. These
* restrictions allows a very quick update across scale space.
*
* @author Peter Abeles
*/
public class ExamplePyramidDiscrete<T extends ImageGray<T>> {
// specifies the image type
Class<T> imageType;
public ExamplePyramidDiscrete( Class<T> imageType ) {
this.imageType = imageType;
}
/**
* Updates and displays the pyramid.
*/
public void process( BufferedImage image ) {
T input = ConvertBufferedImage.convertFromSingle(image, null, imageType);
PyramidDiscrete<T> pyramid = FactoryPyramid.discreteGaussian(
ConfigDiscreteLevels.levels(4), -1, 2, true, ImageType.single(imageType));
pyramid.process(input);
var gui = new DiscretePyramidPanel<T>();
gui.setPyramid(pyramid);
gui.render();
ShowImages.showWindow(gui, "Image Pyramid");
// To get an image at any of the scales simply call this get function
T imageAtScale = pyramid.getLayer(1);
ShowImages.showWindow(ConvertBufferedImage.convertTo(imageAtScale, null, true), "Image at layer 1");
}
public static void main( String[] args ) {
BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample("standard/barbara.jpg"));
var app = new ExamplePyramidDiscrete<>(GrayF32.class);
// var app = new ExamplePyramidDiscrete<>(GrayU8.class);
app.process(image);
}
}
Image Pyramid Float
/**
* Demonstrates how to construct and display a {@link PyramidFloat}. Float pyramids require only require
* that each layer's scale be larger than the scale of the previous layer. Interpolation is used to allow
* sub-sampling at arbitrary scales. All of this additional flexibility comes at the cost of speed
* when compared to a {@link PyramidDiscrete}.
*
* @author Peter Abeles
*/
public class ExamplePyramidFloat<T extends ImageGray<T>> {
// specifies the image type
Class<T> imageType;
// The pyramid data structure
PyramidFloat<T> pyramid;
public ExamplePyramidFloat( Class<T> imageType ) {
this.imageType = imageType;
}
/**
* Creates a fairly standard pyramid and updater.
*/
public void standard() {
// Scale factory for each layer can be any floating point value which is larger than
// the previous layer's scale.
double[] scales = new double[]{1, 1.5, 2, 2.5, 3, 5, 8, 15};
// the amount of blur which is applied to each layer in the pyramid after the previous layer has been sampled
double[] sigmas = new double[]{1, 1, 1, 1, 1, 1, 1, 1};
pyramid = FactoryPyramid.floatGaussian(scales, sigmas, imageType);
}
/**
* Updates and displays the pyramid.
*/
public void process( BufferedImage image ) {
T input = ConvertBufferedImage.convertFromSingle(image, null, imageType);
pyramid.process(input);
ImagePyramidPanel<T> gui = new ImagePyramidPanel<>();
gui.set(pyramid, true);
gui.render();
ShowImages.showWindow(gui, "Image Pyramid Float");
// To get an image at any of the scales simply call this get function
T imageAtScale = pyramid.getLayer(1);
ShowImages.showWindow(ConvertBufferedImage.convertTo(imageAtScale, null, true), "Image at layer 1");
}
public static void main( String[] args ) {
BufferedImage image = UtilImageIO.loadImageNotNull(UtilIO.pathExample("standard/barbara.jpg"));
var app = new ExamplePyramidFloat<>(GrayF32.class);
// var app = new ExamplePyramidFloat<>(GrayU8.class);
app.standard();
app.process(image);
}
}