boofcv.struct.image.Planar Maven / Gradle / Ivy
Show all versions of boofcv-ip Show documentation
/*
* Copyright (c) 2011-2017, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.struct.image;
import boofcv.core.image.GeneralizedImageOps;
import java.lang.reflect.Array;
/**
*
* Multi-band image composed of discontinuous planar images for each band. The bands are discontinuous in that
* each one is an independent memory and are of type {@link ImageGray}. Planar images fully supports all
* functions inside of {@link ImageBase}. Each internal image has the same width, height, startIndex, and stride.
*
*
*
* For example, in a RGB image there would be three bands one for each color,
* and each color would be stored in its own gray scale image. To access the image for a particular
* band call {@link #getBand(int)}. To get the RGB value for a pixel (x,y) one would need to:
*
* int red = image.getBand(0).get(x,y);
* int green = image.getBand(1).get(x,y);
* int blue = image.getBand(2).get(x,y);
*
* Setting the RGB value of pixel (x,y) is done in a similar manner:
*
* image.getBand(0).set(x,y,red);
* image.getBand(1).set(x,y,green);
* image.getBand(2).set(x,y,blue);
*
*
*
*
* May image processing operations can be run independently on each color band. This is useful since many
* operations have been written for {@link ImageGray}, but not Planar yet.
*
* for( int i = 0; i < image.numBands(); i++ ) {
* SomeGrayImageFilter.process( image.getBand(0) );
* }
*
*
*
* @author Peter Abeles
*/
public class Planar> extends ImageMultiBand>{
/**
* Type of image in each band
*/
public Class type;
/**
* Set of gray scale images
*/
public T bands[];
/**
* Creates a Planar image with the specified properties.
*
* @param type The type of image which each band is stored as.
* @param width Width of the image.
* @param height Height of the image.
* @param numBands Total number of bands.
*/
public Planar(Class type, int width, int height, int numBands) {
this.type = type;
this.stride = width;
this.width = width;
this.height = height;
this.bands = (T[]) Array.newInstance(type, numBands);
for (int i = 0; i < numBands; i++) {
bands[i] = GeneralizedImageOps.createSingleBand(type, width, height);
}
this.imageType = ImageType.pl(numBands,type);
}
/**
* Declares internal arrays for storing each band, but not the images in each band.
*
* @param type The type of image which each band is stored as.
* @param numBands Number of bands in the image.
*/
public Planar(Class type, int numBands) {
this.type = type;
this.bands = (T[]) Array.newInstance(type, numBands);
this.imageType = ImageType.pl(numBands,type);
}
/**
* Type of image each band is stored as.
*
* @return The type of ImageGray which each band is stored as.
*/
public Class getBandType() {
return type;
}
/**
* Returns the number of bands or colors stored in this image.
*
* @return Number of bands in the image.
*/
@Override
public int getNumBands() {
return bands.length;
}
/**
* Returns a band in the multi-band image.
*
* @param band Which band should be returned.
* @return Image band
*/
public T getBand(int band) {
if (band >= bands.length || band < 0)
throw new IllegalArgumentException("The specified band is out of bounds: "+band);
return bands[band];
}
/**
* Creates a sub-image from 'this' image. The subimage will share the same internal array
* that stores each pixel's value, but will only pertain to an axis-aligned rectangular segment
* of the original.
*
*
* @param x0 x-coordinate of top-left corner of the sub-image.
* @param y0 y-coordinate of top-left corner of the sub-image.
* @param x1 x-coordinate of bottom-right corner of the sub-image.
* @param y1 y-coordinate of bottom-right corner of the sub-image.
* @param subimage
* @return A sub-image of this image.
*/
@Override
public Planar subimage(int x0, int y0, int x1, int y1, Planar subimage) {
if (x0 < 0 || y0 < 0)
throw new IllegalArgumentException("x0 or y0 is less than zero");
if (x1 < x0 || y1 < y0)
throw new IllegalArgumentException("x1 or y1 is less than x0 or y0 respectively");
if (x1 > width || y1 > height)
throw new IllegalArgumentException("x1 or y1 is more than the width or height respectively");
Planar ret = new Planar<>(type, bands.length);
ret.stride = Math.max(width, stride);
ret.width = x1 - x0;
ret.height = y1 - y0;
ret.startIndex = startIndex + y0 * stride + x0;
ret.subImage = true;
for( int i = 0; i < bands.length; i++ ) {
ret.bands[i] = (T)bands[i].subimage(x0,y0,x1,y1);
}
return ret;
}
/**
* Sets the values of each pixel equal to the pixels in the specified matrix.
* Automatically resized to match the input image.
*
* @param orig The original image whose value is to be copied into this one
*/
@Override
public void setTo( Planar orig) {
if (orig.width != width || orig.height != height)
reshape(orig.width,orig.height);
if( orig.getBandType() != getBandType() )
throw new IllegalArgumentException("The band type must be the same");
int N = orig.getNumBands();
if( N != getNumBands() ) {
setNumberOfBands(orig.getNumBands());
}
for( int i = 0; i < N; i++ ) {
bands[i].setTo(orig.getBand(i));
}
}
/**
* Changes the image's width and height without declaring new memory. If the internal array
* is not large enough to store the new image an IllegalArgumentException is thrown.
*
* @param width The new width.
* @param height The new height.
*/
@Override
public void reshape(int width, int height) {
for( int i = 0; i < bands.length; i++ ) {
bands[i].reshape(width,height);
}
this.startIndex = 0;
this.stride = width;
this.width = width;
this.height = height;
}
/**
* Creates a new image of the same type and number of bands
*
* @param imgWidth image width
* @param imgHeight image height
* @return new image
*/
@Override
public Planar createNew(int imgWidth, int imgHeight) {
return new Planar<>(type, imgWidth, imgHeight, bands.length);
}
/**
* Returns a new {@link Planar} which references the same internal single band images at this one.
*
* @param which List of bands which will comprise the new image
* @return New image
*/
public Planar partialSpectrum(int ...which ) {
Planar out = new Planar<>(getBandType(), which.length);
out.setWidth(width);
out.setHeight(height);
out.setStride(stride);
for (int i = 0; i < which.length; i++) {
out.setBand(i,getBand(which[i]));
}
return out;
}
/**
* Changes the bands order
* @param order The new band order
*/
public void reorderBands( int ...order ) {
T[] bands = (T[]) Array.newInstance(type, order.length);
for (int i = 0; i < order.length; i++) {
bands[i] = this.bands[order[i]];
}
this.bands = bands;
}
/**
* Changes the number of bands in the image. A new array is declared and individual bands are recycled
* if possible
* @param numberOfBands New number of bands in the image.
*/
@Override
public void setNumberOfBands( int numberOfBands ) {
if( numberOfBands == this.bands.length )
return;
T[] bands = (T[]) Array.newInstance(type, numberOfBands);
int N = Math.min(numberOfBands, this.bands.length );
for (int i = 0; i < N; i++) {
bands[i] = this.bands[i];
}
for (int i = N; i < bands.length; i++) {
bands[i] = GeneralizedImageOps.createSingleBand(type, width, height);
}
this.bands = bands;
}
public void setBandType(Class type) {
this.type = type;
}
public T[] getBands() {
return bands;
}
public void setBands(T[] bands) {
this.bands = bands;
}
public void setBand( int which , T image ) {
this.bands[which] = image;
}
}