All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jaitools.imageutils.ImageUtils Maven / Gradle / Ivy

/*
 * Copyright 2009 Michael Bedward
 * 
 * This file is part of jai-tools.

 * jai-tools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.

 * jai-tools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public 
 * License along with jai-tools.  If not, see .
 * 
 */

package jaitools.imageutils;

import jaitools.CollectionFactory;
import java.awt.Color;
import java.awt.image.RenderedImage;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import javax.media.jai.JAI;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.RenderedOp;
import javax.media.jai.TiledImage;
import javax.media.jai.iterator.RectIterFactory;
import javax.media.jai.iterator.WritableRectIter;

/**
 * Static helper functions for common image tasks.
 * 
 * @author Michael Bedward
 * @since 1.0
 * @source $URL: https://jai-tools.googlecode.com/svn/tags/1.0.0/utils/src/main/java/jaitools/imageutils/ImageUtils.java $
 * @version $Id: ImageUtils.java 1100 2010-02-10 07:28:08Z michael.bedward $
 */
public class ImageUtils {

    /**
     * Creates a new TiledImage object with a single band filled with zero
     * values
     * @param width image width in pixels
     * @param height image height in pixels
     * @return a new TiledImage object
     *
     * @deprecated This method will be removed in version 1.1.
     *             Please use {@linkplain #createConstantImage(int, int, java.lang.Number)}
     */
    public static TiledImage createDoubleImage(int width, int height) {
        return createDoubleImage(width, height, new double[] {0});
    }

    /**
     * Creates a new TiledImage object with one or more bands filled with zero
     * values
     * @param width image width in pixels
     * @param height image height in pixels
     * @param numBands number of image bands (must be >= 1)
     * @return a new TiledImage object
     *
     * @deprecated This method will be removed in version 1.1.
     *             Please use {@linkplain #createConstantImage(int, int, java.lang.Number)}
     */
    public static TiledImage createDoubleImage(int width, int height, int numBands) {
        if (numBands < 1) {
            throw new IllegalArgumentException("numBands must be at least 1");
        }
        
        double[] bandValues = new double[numBands];
        for (int i = 0; i < numBands; i++) { bandValues[i] = 0d; }
        return createDoubleImage(width, height, bandValues);
    }

    
    /**
     * Creates a new TiledImage object with one or more bands of constant value.
     * The number of bands in the output image corresponds to the length of
     * the input values array
     * @param width image width in pixels
     * @param height image height in pixels
     * @param values array of double values (must contain at least one element)
     * @return a new TiledImage object
     *
     * @deprecated This method will be removed in version 1.1.
     *             Please use {@linkplain #createConstantImage(int width, int height, Number[] values)}
     */
    public static TiledImage createDoubleImage(int width, int height, double[] values) {
        if (values == null || values.length < 1) {
            throw new IllegalArgumentException("values array must contain at least 1 value");
        }
        
        Double[] dvalues = new Double[values.length];
        for (int i = 0; i < values.length; i++) {
            dvalues[i] = Double.valueOf(values[i]);
        }
        
        ParameterBlockJAI pb = new ParameterBlockJAI("constant");
        pb.setParameter("width", (float)width);
        pb.setParameter("height", (float)height);
        pb.setParameter("bandValues", dvalues);
        
        RenderedOp op = JAI.create("constant", pb);
        return new TiledImage(op, false);
    }

    /**
     * Creates a new TiledImage object with a single band of constant value.
     * The data type of the image corresponds to the class of {@code value}.
     *
     * @param width image width in pixels
     *
     * @param height image height in pixels
     *
     * @param value the constant value to fill the image
     *
     * @return a new TiledImage object
     */
    public static TiledImage createConstantImage(int width, int height, Number value) {
        return createConstantImage(width, height, new Number[] {value});
    }

    /**
     * Creates a new TiledImage object with one or more bands of constant value.
     * The number of bands in the output image corresponds to the length of
     * the input values array and the data type of the image corresponds to the
     * {@code Number} class used.
     *
     * @param width image width in pixels
     *
     * @param height image height in pixels
     *
     * @param values array of values (must contain at least one element)
     *
     * @return a new TiledImage object
     */
    public static TiledImage createConstantImage(int width, int height, Number[] values) {
        if (values == null || values.length < 1) {
            throw new IllegalArgumentException("values array must contain at least 1 value");
        }

        ParameterBlockJAI pb = new ParameterBlockJAI("constant");
        pb.setParameter("width", (float)width);
        pb.setParameter("height", (float)height);

        Number[] typedValues = null;
        if (values[0] instanceof Double) {
            typedValues = new Double[values.length];
        } else if (values[0] instanceof Float) {
            typedValues = new Float[values.length];
        } else if (values[0] instanceof Integer) {
            typedValues = new Integer[values.length];
        } else if (values[0] instanceof Short) {
            typedValues = new Short[values.length];
        } else if (values[0] instanceof Byte) {
            typedValues = new Byte[values.length];
        } else {
            throw new UnsupportedOperationException("Unsupported data type: " +
                    values[0].getClass().getName());
        }

        for (int i = 0; i < values.length; i++) {
            typedValues[i] = values[i];
        }
        
        pb.setParameter("bandValues", typedValues);

        RenderedOp op = JAI.create("constant", pb);
        return new TiledImage(op, false);
    }
    
    /**
     * Create a set of colours using a simple colour ramp algorithm in the HSB colour space.
     *
     * @param numColours number of colours required
     *
     * @return an array of colours sampled from the HSB space.
     */
    public static Color[] createRampColours(int numColours) {
        return createRampColours(numColours, 0.8f, 0.8f);
    }

    /**
     * Create a set of colours using a simple colour ramp algorithm in the HSB colour space.
     *
     * @param numColours number of colours required
     *
     * @param saturation the saturation of all colours (between 0 and 1)
     *
     * @param brightness the brightness of all colours (between 0 and 1)
     *
     * @return an array of colours sampled from the HSB space between the start and end hues
     */
    public static Color[] createRampColours(int numColours, float saturation, float brightness) {
        return createRampColours(numColours, 0.0f, 1.0f, saturation, brightness);
    }

    /**
     * Create a set of colours using a simple colour ramp algorithm in the HSB colour space.
     * All float arguments should be values between 0 and 1.
     *
     * @param numColours number of colours required
     *
     * @param startHue the starting hue
     *
     * @param endHue the ending hue
     *
     * @param saturation the saturation of all colours
     *
     * @param brightness the brightness of all colours
     *
     * @return an array of colours sampled from the HSB space between the start and end hues
     */
    public static Color[] createRampColours(int numColours, float startHue, float endHue,
            float saturation, float brightness) {

        Color[] colors = new Color[numColours];

        final float increment = numColours > 1 ? (endHue - startHue) / (float)(numColours - 1) : 0f;
        float hue = startHue;
        for (int i = 0; i < numColours; i++) {
            int rgb = Color.HSBtoRGB(hue, saturation, brightness);
            colors[i] = new Color(rgb);
            hue += increment;
        }

        return colors;
    }

    /**
     * A helper method that creates a 3-band colour image, using a colour ramp,
     * for a data image with integral data type and pixel values between 1 and
     * {@code ncol-1}.
     * 

* This method is only preliminary and, presently, very limited in the * input images that it will deal with. * * @param dataImg the data image: presently assumed to be single-band with * an integral data type * * @param ncol number of colours to be created using a colour ramp * * @return a three band image with an RGB ColorModel * * @deprecated This method will be removed in version 1.1. * Please use {@linkplain #createDisplayImage(RenderedImage, Map)} instead. * Colour ramp colours can be generated with * {@linkplain #createRampColours(int)}. */ public static RenderedImage createDisplayImage(RenderedImage dataImg, int ncol) { byte[][] lookup = new byte[3][ncol]; float hue = 0f; float hueIncr = 1f / (float)ncol; for (int i = 0; i < ncol; i++) { int colour = Color.HSBtoRGB(hue, 0.7f, 0.7f); lookup[0][i] = (byte) ((colour & 0x00ff0000) >> 16); lookup[1][i] = (byte) ((colour & 0x0000ff00) >> 8); lookup[2][i] = (byte) (colour & 0x000000ff); hue += hueIncr; } ParameterBlockJAI pb = new ParameterBlockJAI("lookup"); pb.setSource("source0", dataImg); pb.setParameter("table", new LookupTableJAI(lookup, 1)); RenderedOp displayImg = JAI.create("lookup", pb); return displayImg; } /** * Creates a proxy RGB display image for the given data image. The data image should be * of integral data type. Only the first band of multi-band images will be used. * * @param dataImg the data image * * @param colourTable a lookup table giving colours for each data image value * * @return a new RGB image */ public static RenderedImage createDisplayImage(RenderedImage dataImg, Map colourTable) { if (colourTable.size() > 256) { throw new IllegalArgumentException("Number of colours can't be more than 256"); } Integer maxKey = null; Integer minKey = null; for (Integer key : colourTable.keySet()) { if (minKey == null) { minKey = maxKey = key; } else if (key < minKey) { minKey = key; } else if (key > maxKey) { maxKey = key; } } ParameterBlockJAI pb = null; RenderedImage lookupImg = dataImg; byte[][] lookup = null; int offset = 0; if (minKey < 0 || maxKey > 255) { lookupImg = createConstantImage(dataImg.getWidth(), dataImg.getHeight(), Integer.valueOf(0)); SortedMap keyTable = CollectionFactory.sortedMap(); int k = 0; for (Integer key : colourTable.keySet()) { keyTable.put(key, k++); } WritableRectIter iter = RectIterFactory.createWritable((TiledImage)lookupImg, null); do { do { do { iter.setSample( keyTable.get(iter.getSample()) ); } while (!iter.nextPixelDone()); iter.startPixels(); } while (!iter.nextLineDone()); iter.startLines(); } while (!iter.nextBandDone()); lookup = new byte[3][colourTable.size()]; for (Integer key : keyTable.keySet()) { int index = keyTable.get(key); int colour = colourTable.get(key).getRGB(); lookup[0][index] = (byte) ((colour & 0x00ff0000) >> 16); lookup[1][index] = (byte) ((colour & 0x0000ff00) >> 8); lookup[2][index] = (byte) (colour & 0x000000ff); } } else { lookup = new byte[3][maxKey - minKey + 1]; offset = minKey; for (Integer key : colourTable.keySet()) { int colour = colourTable.get(key).getRGB(); lookup[0][key - offset] = (byte) ((colour & 0x00ff0000) >> 16); lookup[1][key - offset] = (byte) ((colour & 0x0000ff00) >> 8); lookup[2][key - offset] = (byte) (colour & 0x000000ff); } } pb = new ParameterBlockJAI("Lookup"); pb.setSource("source0", lookupImg); pb.setParameter("table", new LookupTableJAI(lookup, offset)); RenderedOp displayImg = JAI.create("Lookup", pb); return displayImg; } /** * Get the bands of a multi-band image as a list of single-band images. This can * be used, for example, to separate the result image returned by the KernelStats * operator into separate result images. * * @param img the multi-band image * @return a List of new single-band images */ public static List getBandsAsImages(RenderedImage img) { List images = CollectionFactory.list(); if (img != null) { int numBands = img.getSampleModel().getNumBands(); for (int band = 0; band < numBands; band++) { ParameterBlockJAI pb = new ParameterBlockJAI("BandSelect"); pb.setSource("source0", img); pb.setParameter("bandindices", new int[]{band}); RenderedImage bandImg = JAI.create("BandSelect", pb); images.add(bandImg); } } return images; } /** * Get the specified bands of a multi-band image as a list of single-band images. This can * be used, for example, to separate the result image returned by the KernelStats * operator into separate result images. * * @param img the multi-band image * @param bandIndices a Collection of Integer indices in the range 0 <= i < number of bands * @return a List of new single-band images */ public static List getBandsAsImages(RenderedImage img, Collection bandIndices) { List images = CollectionFactory.list(); if (img != null) { int numBands = img.getSampleModel().getNumBands(); SortedSet sortedIndices = CollectionFactory.sortedSet(); sortedIndices.addAll(bandIndices); if (sortedIndices.first() < 0 || sortedIndices.last() >= numBands) { throw new IllegalArgumentException("band index out of bounds"); } for (Integer band : sortedIndices) { ParameterBlockJAI pb = new ParameterBlockJAI("BandSelect"); pb.setSource("source0", img); pb.setParameter("bandindices", new int[]{band}); RenderedImage bandImg = JAI.create("BandSelect", pb); images.add(bandImg); } } return images; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy