boofcv.core.image.GConvertImage Maven / Gradle / Ivy
Show all versions of boofcv-ip Show documentation
/*
* Copyright (c) 2022, 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.core.image;
import boofcv.alg.InputSanityCheck;
import boofcv.alg.misc.GImageMiscOps;
import boofcv.struct.image.*;
import java.lang.reflect.Method;
/**
*
* Generalized functions for converting between different image types. Numerical values do not change or are closely
* approximated in these functions. If an output image is not specified then a new instance is declared and returned.
*
*
* @author Peter Abeles
*/
@SuppressWarnings("unchecked")
public class GConvertImage {
/**
*
* Converts one type of between two types of images using a default method. Both are the same image type
* then a simple type cast if performed at the pixel level. If the input is multi-band and the output
* is single band then it will average the bands. If input is single band and output is multi-band
* then the single band is copied into each of the other bands.
*
*
*
* In some cases a temporary image will be created to store intermediate results. If this is an issue
* you will need to create a specialized conversion algorithm.
*
*
* @param input Input image which is being converted. Not modified.
* @param output (Optional) The output image. If null a new image is created. Modified.
*/
public static void convert( ImageBase input, ImageBase output ) {
ImageType typeIn = input.getImageType();
ImageType typeOut = output.getImageType();
if (input instanceof ImageGray) {
ImageGray sb = (ImageGray)input;
if (output instanceof ImageGray) {
if (input.getClass() == output.getClass()) {
output.setTo(input);
} else {
try {
Method m = ConvertImage.class.getMethod("convert", input.getClass(), output.getClass());
m.invoke(null, input, output);
} catch (Exception e) {
throw new IllegalArgumentException("Unknown conversion. " +
input.getClass().getSimpleName() + " to " + output.getClass().getSimpleName());
}
}
} else if (output instanceof Planar) {
Planar ms = (Planar)output;
for (int i = 0; i < ms.getNumBands(); i++) {
convert(input, ms.getBand(i));
}
} else if (output instanceof ImageInterleaved) {
ImageInterleaved il = (ImageInterleaved)output;
for (int i = 0; i < il.getNumBands(); i++) {
GImageMiscOps.insertBand(sb, i, il);
}
} else {
throw new IllegalArgumentException("Unknown conversion. " +
input.getClass().getSimpleName() + " to " + output.getClass().getSimpleName());
}
} else if (input instanceof ImageInterleaved && output instanceof ImageInterleaved) {
if (input.getClass() == output.getClass()) {
output.setTo(input);
} else {
try {
Method m = ConvertImage.class.getMethod("convert", input.getClass(), output.getClass());
m.invoke(null, input, output);
} catch (Exception e) {
throw new IllegalArgumentException("Unknown conversion. " +
input.getClass().getSimpleName() + " to " + output.getClass().getSimpleName());
}
}
} else if (input instanceof Planar && output instanceof ImageGray) {
Planar mi = (Planar)input;
ImageGray so = (ImageGray)output;
if (mi.getImageType().getDataType() != so.getDataType()) {
int w = output.width;
int h = output.height;
ImageGray tmp = GeneralizedImageOps.createSingleBand(mi.getImageType().getDataType(), w, h);
average(mi, tmp);
convert(tmp, so);
} else {
average(mi, so);
}
} else if (input instanceof Planar && output instanceof ImageInterleaved) {
String functionName;
if (typeIn.getDataType() == typeOut.getDataType()) {
functionName = "convert";
} else {
functionName = "convert" + typeIn.getDataType() + typeOut.getDataType();
}
try {
Method m = ConvertImage.class.getMethod(functionName, input.getClass(), output.getClass());
m.invoke(null, input, output);
} catch (Exception e) {
throw new IllegalArgumentException("Unknown conversion. " +
input.getClass().getSimpleName() + " to " + output.getClass().getSimpleName());
}
} else if (input instanceof Planar && output instanceof Planar) {
Planar mi = (Planar)input;
Planar mo = (Planar)output;
if (mi.getBandType() == mo.getBandType()) {
mo.setTo(mi);
} else {
for (int i = 0; i < mi.getNumBands(); i++) {
convert(mi.getBand(i), mo.getBand(i));
}
}
} else if (input instanceof ImageInterleaved && output instanceof Planar) {
String functionName;
if (typeIn.getDataType() == typeOut.getDataType()) {
functionName = "convert";
} else {
functionName = "convert" + typeIn.getDataType() + typeOut.getDataType();
}
try {
Method m = ConvertImage.class.getMethod(functionName, input.getClass(), output.getClass());
m.invoke(null, input, output);
} catch (Exception e) {
throw new IllegalArgumentException("Unknown conversion. " +
input.getClass().getSimpleName() + " to " + output.getClass().getSimpleName());
}
} else if (input instanceof ImageInterleaved && output instanceof ImageGray) {
ImageInterleaved mb = (ImageInterleaved)input;
ImageGray so = (ImageGray)output;
if (mb.getImageType().getDataType() != so.getDataType()) {
int w = output.width;
int h = output.height;
ImageGray tmp = GeneralizedImageOps.createSingleBand(mb.getImageType().getDataType(), w, h);
average(mb, tmp);
convert(tmp, so);
} else {
average(mb, so);
}
} else {
String nameInput = input.getClass().getSimpleName();
String nameOutput = output.getClass().getSimpleName();
throw new IllegalArgumentException("Don't know how to convert between input types. " + nameInput + " " + nameOutput);
}
}
/**
* Converts a {@link ImageMultiBand} into a {@link ImageGray} by computing the average value of each pixel
* across all the bands.
*
* @param input ImageMultiBand that is being converted. Not modified.
* @param output (Optional) The single band output image. If null a new image is created. Modified.
* @return Converted image.
*/
public static > T average( ImageMultiBand input, T output ) {
if (input instanceof Planar) {
return (T)average((Planar)input, output);
} else if (input instanceof ImageInterleaved) {
return (T)average((ImageInterleaved)input, output);
} else {
throw new RuntimeException("Unknown multiband image");
}
}
/**
* Converts a {@link Planar} into a {@link ImageGray} by computing the average value of each pixel
* across all the bands.
*
* @param input Input Planar image that is being converted. Not modified.
* @param output (Optional) The single band output image. If null a new image is created. Modified.
* @return Converted image.
*/
public static > T average( Planar input, T output ) {
Class type = input.getBandType();
if (type == GrayU8.class) {
return (T)ConvertImage.average((Planar)input, (GrayU8)output);
} else if (type == GrayS8.class) {
return (T)ConvertImage.average((Planar)input, (GrayS8)output);
} else if (type == GrayU16.class) {
return (T)ConvertImage.average((Planar)input, (GrayU16)output);
} else if (type == GrayS16.class) {
return (T)ConvertImage.average((Planar)input, (GrayS16)output);
} else if (type == GrayS32.class) {
return (T)ConvertImage.average((Planar)input, (GrayS32)output);
} else if (type == GrayS64.class) {
return (T)ConvertImage.average((Planar)input, (GrayS64)output);
} else if (type == GrayF32.class) {
return (T)ConvertImage.average((Planar)input, (GrayF32)output);
} else if (type == GrayF64.class) {
return (T)ConvertImage.average((Planar)input, (GrayF64)output);
} else {
throw new IllegalArgumentException("Unknown image type: " + type.getSimpleName());
}
}
/**
* Converts a {@link Planar} into a {@link ImageGray} by computing the average value of each pixel
* across all the bands.
*
* @param input Input Planar image that is being converted. Not modified.
* @param output (Optional) The single band output image. If null a new image is created. Modified.
* @return Converted image.
*/
public static > T average( ImageInterleaved input, T output ) {
ImageDataType type = input.getImageType().getDataType();
if (type == ImageDataType.U8) {
return (T)ConvertImage.average((InterleavedU8)input, (GrayU8)output);
} else if (type == ImageDataType.S8) {
return (T)ConvertImage.average((InterleavedS8)input, (GrayS8)output);
} else if (type == ImageDataType.U16) {
return (T)ConvertImage.average((InterleavedU16)input, (GrayU16)output);
} else if (type == ImageDataType.S16) {
return (T)ConvertImage.average((InterleavedS16)input, (GrayS16)output);
} else if (type == ImageDataType.S32) {
return (T)ConvertImage.average((InterleavedS32)input, (GrayS32)output);
} else if (type == ImageDataType.S64) {
return (T)ConvertImage.average((InterleavedS64)input, (GrayS64)output);
} else if (type == ImageDataType.F32) {
return (T)ConvertImage.average((InterleavedF32)input, (GrayF32)output);
} else if (type == ImageDataType.F64) {
return (T)ConvertImage.average((InterleavedF64)input, (GrayF64)output);
} else {
throw new IllegalArgumentException("Unknown image type: " + type);
}
}
/**
* Converts pixel values in the input image into an integer values from 0 to numValues.
*
* @param input Input image
* @param min minimum input pixel value, inclusive
* @param max maximum input pixel value, inclusive
* @param numValues Number of possible pixel values in output image
* @param output (Optional) Storage for the output image. Can be null.
* @return The converted output image.
*/
public static GrayU8 convert( ImageGray input, double min, double max, int numValues, GrayU8 output ) {
// see if it can use the faster straight forward convert
if (min == 0 && max == 255 && numValues == 256) {
if (output == null)
output = new GrayU8(input.width, input.height);
convert(input, output);
return output;
}
ImageDataType type = input.getImageType().getDataType();
if (type == ImageDataType.U8) {
return ConvertImage.convert((GrayU8)input, (int)min, (int)max, numValues, output);
} else if (type == ImageDataType.S8) {
return ConvertImage.convert((GrayS8)input, (int)min, (int)max, numValues, output);
} else if (type == ImageDataType.U16) {
return ConvertImage.convert((GrayU16)input, (int)min, (int)max, numValues, output);
} else if (type == ImageDataType.S16) {
return ConvertImage.convert((GrayS16)input, (int)min, (int)max, numValues, output);
} else if (type == ImageDataType.S32) {
return ConvertImage.convert((GrayS32)input, (int)min, (int)max, numValues, output);
} else if (type == ImageDataType.S64) {
return ConvertImage.convert((GrayS64)input, (long)min, (long)max, numValues, output);
} else if (type == ImageDataType.F32) {
return ConvertImage.convert((GrayF32)input, (float)min, (float)max, numValues, output);
} else if (type == ImageDataType.F64) {
return ConvertImage.convert((GrayF64)input, min, max, numValues, output);
} else {
throw new IllegalArgumentException("Unknown image type: " + type);
}
}
/**
* Converts an image from one type to another type. Creates a new image instance if
* an output is not provided.
*
* @param src Input image. Not modified.
* @param dst Converted output image. If null a new one will be declared. Modified.
* @param typeDst The type of output image.
* @return Converted image.
*/
public static > T convert( ImageGray> src, T dst, Class typeDst ) {
if (dst == null) {
dst = (T)GeneralizedImageOps.createSingleBand(typeDst, src.width, src.height);
} else {
InputSanityCheck.checkSameShape(src, dst);
}
convert(src, dst);
return dst;
}
}