001: /*
002: * $RCSfile: MatchCDFCRIF.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:31 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.RenderingHints;
015: import java.awt.image.RenderedImage;
016: import java.awt.image.renderable.ParameterBlock;
017: import javax.media.jai.CRIFImpl;
018: import javax.media.jai.Histogram;
019: import javax.media.jai.ImageLayout;
020: import java.util.Map;
021:
022: /**
023: * A <code>CRIF</code> supporting the "MatchCDF" operation in the rendered
024: * and renderable image layers.
025: *
026: * @see javax.media.jai.operator.MatchCDFDescriptor
027: * @see javax.media.jai.operator.PiecewiseDescriptor
028: * @see PiecewiseOpImage
029: *
030: *
031: * @since EA4
032: */
033: public class MatchCDFCRIF extends CRIFImpl {
034: /*
035: * Creates a piecewise mapping from an image with cumulative distribution
036: * function of pixel values CDFin to another given by CDFout.
037: */
038: private static void createHistogramMap(float[] CDFin,
039: float[] CDFout, double lowValue, double binWidth,
040: int numBins, float[] abscissa, float[] ordinate) {
041: // Initialize the first abscissa and the output CDF index.
042: double x = lowValue;
043: int j = 0;
044: int jMax = numBins - 1;
045:
046: // Generate one breakpoint for each bin.
047: for (int i = 0; i < numBins; i++) {
048: // Find the first output bin such that the output CDF is
049: // greater than or equal to the input CDF at the current bin.
050: float w = CDFin[i];
051: while (CDFout[j] < w && j < jMax)
052: j++;
053:
054: // Set the breakpoint values.
055: abscissa[i] = (float) x;
056: ordinate[i] = (float) (j * binWidth);
057:
058: // Increment the abscissa.
059: x += binWidth;
060: }
061: }
062:
063: /**
064: * Create a set of breakpoints which will map the input histogram to
065: * an output histogram with the specified cumulative distribution function.
066: *
067: * @param histIn The input histogram.
068: * @param CDFOut The output CDF.
069: * @return A piecewise transform which will modify the input histogram
070: * to match the output CDF.
071: */
072: private static float[][][] createSpecificationMap(Histogram histIn,
073: float[][] CDFOut) {
074: // Allocate the overall breakpoint array.
075: int numBands = histIn.getNumBands();
076: float[][][] bp = new float[numBands][][];
077:
078: // Calculate a different set of breakpoints for each band.
079: float[] CDFin = null;
080: for (int band = 0; band < numBands; band++) {
081: // Allocate memory for the breakpoints for this band.
082: int numBins = histIn.getNumBins(band);
083: bp[band] = new float[2][];
084: bp[band][0] = new float[numBins];
085: bp[band][1] = new float[numBins];
086:
087: // Calculate the total count over all bins of this band.
088: int[] binsIn = histIn.getBins(band);
089: long binTotalIn = binsIn[0];
090: for (int i = 1; i < numBins; i++) {
091: binTotalIn += binsIn[i];
092: }
093:
094: // Allocate memory for the CDF for this band only if needed.
095: if (CDFin == null || CDFin.length < numBins) {
096: CDFin = new float[numBins];
097: }
098:
099: // Calculate the Cumulative Distribution Function (CDF) for the
100: // input histogram for this band.
101: CDFin[0] = (float) binsIn[0] / binTotalIn;
102: for (int i = 1; i < numBins; i++) {
103: CDFin[i] = CDFin[i - 1] + (float) binsIn[i]
104: / binTotalIn;
105: }
106:
107: // Calculate the mapping function.
108: double binWidth = (histIn.getHighValue(band) - histIn
109: .getLowValue(band))
110: / numBins;
111: createHistogramMap(CDFin, CDFOut.length > 1 ? CDFOut[band]
112: : CDFOut[0], histIn.getLowValue(band), binWidth,
113: numBins, bp[band][0], bp[band][1]);
114: }
115:
116: return bp;
117: }
118:
119: /** Constructor. */
120: public MatchCDFCRIF() {
121: super ("matchcdf");
122: }
123:
124: /**
125: * Creates a new instance of <code>PiecewiseOpImage</code> in the
126: * rendered layer.
127: *
128: * @param args The source image and the breakpoints.
129: * @param hints Optionally contains destination image layout.
130: */
131: public RenderedImage create(ParameterBlock args,
132: RenderingHints renderHints) {
133: // Get ImageLayout from renderHints if any.
134: ImageLayout layout = RIFUtil.getImageLayoutHint(renderHints);
135:
136: // Derive breakpoints from the histogram and specified CDF.
137: RenderedImage src = args.getRenderedSource(0);
138: Histogram hist = (Histogram) src.getProperty("histogram");
139: float[][] CDF = (float[][]) args.getObjectParameter(0);
140: float[][][] bp = createSpecificationMap(hist, CDF);
141:
142: return new PiecewiseOpImage(src, renderHints, layout, bp);
143: }
144: }
|